fix clippy warnings
[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!(flags == 0 || flags == 0x4000 || flags == 0x8000);
50 validate!((palsize as u64) * 8 + 8 <= size);
51 for i in 0..palsize {
52 let a = br.read_u16be()?;
53 let r = br.read_u16be()?;
54 let g = br.read_u16be()?;
55 let b = br.read_u16be()?;
56 pal[i * 4] = (r >> 8) as u8;
57 pal[i * 4 + 1] = (g >> 8) as u8;
58 pal[i * 4 + 2] = (b >> 8) as u8;
59 if flags == 0x8000 {
60 pal[i * 4 + 3] = (a >> 8) as u8;
61 }
62 }
63 if flags == 0x4000 {
64 br.read_skip(8)?;
65 }
66 Ok(size)
67 }
68
69 struct RootChunkHandler {
70 ctype: u32,
71 parse: fn(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64>,
72 }
73
74 struct TrackChunkHandler {
75 ctype: u32,
76 parse: fn(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64>,
77 }
78
79 const IGNORED_CHUNKS: &[u32] = &[
80 mktag!(b"free"), mktag!(b"skip"), mktag!(b"udta"), mktag!(b"wide")
81 ];
82
83 const ROOT_CHUNK_HANDLERS: &[RootChunkHandler] = &[
84 RootChunkHandler { ctype: mktag!(b"ftyp"), parse: read_ftyp },
85 RootChunkHandler { ctype: mktag!(b"mdat"), parse: read_mdat },
86 RootChunkHandler { ctype: mktag!(b"moov"), parse: read_moov },
87 RootChunkHandler { ctype: mktag!(b"moof"), parse: read_moof },
88 RootChunkHandler { ctype: mktag!(b"sidx"), parse: read_sidx },
89 ];
90
91 fn print_cname(ctype: u32, size: u64, off: u64, depth: u8) {
92 for _ in 0..depth { print!(" "); }
93 let tag = [(ctype >> 24) as u8, (ctype >> 16) as u8, (ctype >> 8) as u8, ctype as u8];
94 let mut printable = true;
95 for ch in tag.iter() {
96 if !(0x20..=0x7F).contains(ch) {
97 printable = false;
98 break;
99 }
100 }
101 if printable {
102 print!(" '{}{}{}{}'", tag[0] as char, tag[1] as char, tag[2] as char, tag[3] as char);
103 } else {
104 print!(" {:08X}", ctype);
105 }
106 println!(" size {} @ {:X}", size, off);
107 }
108
109 macro_rules! read_chunk_list {
110 (root; $name: expr, $fname: ident, $handlers: ident) => {
111 fn $fname(&mut self, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<()> {
112 self.depth += 1;
113 validate!(self.depth < 32);
114 let list_end = self.src.tell() + size;
115 while self.src.tell() < list_end {
116 let ret = read_chunk_header(self.src);
117 if ret.is_err() { break; }
118 let (ctype, size) = ret.unwrap();
119 if self.print_chunks {
120 print_cname(ctype, size, self.src.tell(), self.depth as u8);
121 }
122 if self.src.tell() + size > list_end {
123 break;
124 }
125 if IGNORED_CHUNKS.contains(&ctype) {
126 self.src.skip64(size)?;
127 continue;
128 }
129 let handler = $handlers.iter().find(|x| x.ctype == ctype);
130 let read_size;
131 if let Some(ref handler) = handler {
132 read_size = (handler.parse)(self, strmgr, size)?;
133 } else {
134 println!("skipping unknown chunk {:08X} size {}", ctype, size);
135 read_size = 0;
136 }
137 validate!(read_size <= size);
138 self.src.skip64(size - read_size)?;
139 }
140 self.depth -= 1;
141 validate!(self.src.tell() == list_end);
142 Ok(())
143 }
144 };
145 (track; $name: expr, $fname: ident, $handlers: ident) => {
146 fn $fname(&mut self, br: &mut ByteReader, size: u64) -> DemuxerResult<()> {
147 self.depth += 1;
148 validate!(self.depth < 32);
149 let list_end = br.tell() + size;
150 while br.tell() < list_end {
151 let ret = read_chunk_header(br);
152 if ret.is_err() { break; }
153 let (ctype, size) = ret.unwrap();
154 if self.print_chunks {
155 print_cname(ctype, size, br.tell(), self.depth + 1);
156 }
157 if br.tell() + size > list_end {
158 break;
159 }
160 if IGNORED_CHUNKS.contains(&ctype) {
161 br.skip64(size)?;
162 continue;
163 }
164 let handler = $handlers.iter().find(|x| x.ctype == ctype);
165 let read_size;
166 if let Some(ref handler) = handler {
167 read_size = (handler.parse)(self, br, size)?;
168 } else {
169 read_size = 0;
170 }
171 validate!(read_size <= size);
172 br.skip64(size - read_size)?;
173 }
174 self.depth -= 1;
175 validate!(br.tell() == list_end);
176 Ok(())
177 }
178 }
179 }
180
181 fn skip_chunk(_track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
182 br.skip64(size)?;
183 Ok(size)
184 }
185
186 fn read_ftyp(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
187 dmx.src.skip64(size)?;
188 Ok(size)
189 }
190
191 fn read_mdat(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
192 dmx.mdat_pos = dmx.src.tell();
193 dmx.mdat_size = size;
194 dmx.src.skip64(size)?;
195 Ok(size)
196 }
197
198 fn read_sidx(_dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, _size: u64) -> DemuxerResult<u64> {
199 Ok(0)
200 }
201
202 fn read_moov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
203 dmx.read_moov(strmgr, size)?;
204 Ok(size)
205 }
206
207 const MOOV_CHUNK_HANDLERS: &[RootChunkHandler] = &[
208 RootChunkHandler { ctype: mktag!(b"mvhd"), parse: read_mvhd },
209 RootChunkHandler { ctype: mktag!(b"cmov"), parse: read_cmov },
210 RootChunkHandler { ctype: mktag!(b"ctab"), parse: read_ctab },
211 RootChunkHandler { ctype: mktag!(b"trak"), parse: read_trak },
212 RootChunkHandler { ctype: mktag!(b"meta"), parse: read_meta },
213 RootChunkHandler { ctype: mktag!(b"mvex"), parse: read_mvex },
214 RootChunkHandler { ctype: mktag!(b"iods"), parse: skip_chunk_mov },
215 ];
216
217 fn read_mvhd(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
218 const KNOWN_MVHD_SIZE: u64 = 100;
219 let br = &mut dmx.src;
220 validate!(size >= KNOWN_MVHD_SIZE);
221 let version = br.read_byte()?;
222 validate!(version == 0);
223 let _flags = br.read_u24be()?;
224 let _ctime = br.read_u32be()?;
225 let _mtime = br.read_u32be()?;
226 let tscale = br.read_u32be()?;
227 let duration = br.read_u32be()?;
228 let _pref_rate = br.read_u32be()?;
229 let _pref_volume = br.read_u16be()?;
230 br.read_skip(10)?;
231 br.read_skip(36)?; // matrix
232 let _preview_time = br.read_u32be()?;
233 let _preview_duration = br.read_u32be()?;
234 let _poster_time = br.read_u32be()?;
235 let _sel_time = br.read_u32be()?;
236 let _sel_duration = br.read_u32be()?;
237 let _cur_time = br.read_u32be()?;
238 let _next_track_id = br.read_u32be()?;
239 dmx.duration = duration;
240 dmx.tb_den = tscale;
241
242 Ok(KNOWN_MVHD_SIZE)
243 }
244
245 fn read_cmov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
246 let br = &mut dmx.src;
247 validate!(size > 24);
248 let dcom_size = br.read_u32be()?;
249 let dcom_tag = br.read_tag()?;
250 let compr_type = br.read_tag()?;
251 validate!(&dcom_tag == b"dcom" && dcom_size == 12);
252 if &compr_type != b"zlib" {
253 return Err(DemuxerError::NotImplemented);
254 }
255 let cmvd_size = u64::from(br.read_u32be()?);
256 let cmvd_tag = br.read_tag()?;
257 validate!(&cmvd_tag == b"cmvd" && cmvd_size > 14 && cmvd_size == size - 12);
258 let comp_size = (cmvd_size - 12) as usize;
259 let uncomp_size = br.read_u32be()? as usize;
260 validate!(uncomp_size > 8);
261 let mut sbuf = vec![0; comp_size];
262 let mut dbuf = vec![0; uncomp_size];
263 br.read_buf(sbuf.as_mut_slice())?;
264 let ret = Inflate::uncompress(sbuf.as_slice(), dbuf.as_mut_slice());
265 if ret.is_err() {
266 return Err(DemuxerError::InvalidData);
267 }
268 let len = ret.unwrap();
269 validate!(len == uncomp_size);
270 let mut mr = MemoryReader::new_read(dbuf.as_slice());
271 let mut br = ByteReader::new(&mut mr);
272 let (ctype, csize) = read_chunk_header(&mut br)?;
273 validate!(ctype == mktag!(b"moov"));
274 let mut ddmx = MOVDemuxer::new(&mut br);
275 ddmx.print_chunks = dmx.print_chunks;
276 ddmx.read_moov(strmgr, csize)?;
277 std::mem::swap(&mut dmx.tracks, &mut ddmx.tracks);
278 dmx.duration = ddmx.duration;
279 dmx.tb_den = ddmx.tb_den;
280 std::mem::swap(&mut dmx.pal, &mut ddmx.pal);
281
282 Ok(size)
283 }
284
285 fn read_ctab(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
286 let mut pal = [0; 1024];
287 let size = read_palette(dmx.src, size, &mut pal)?;
288 dmx.pal = Some(Arc::new(pal));
289 Ok(size)
290 }
291
292 fn read_meta(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
293 dmx.src.skip64(size)?;
294 Ok(size)
295 }
296
297 fn read_mvex(_dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, _size: u64) -> DemuxerResult<u64> {
298 Ok(0)
299 }
300
301 fn skip_chunk_mov(_dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, _size: u64) -> DemuxerResult<u64> {
302 Ok(0)
303 }
304
305 fn read_trak(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
306 let mut track = Track::new(dmx.cur_track as u32, dmx.tb_den);
307 track.print_chunks = dmx.print_chunks;
308 track.read_trak(dmx.src, size)?;
309 validate!(track.tkhd_found && track.stsd_found);
310 validate!(strmgr.get_stream_by_id(track.track_id).is_none());
311 dmx.cur_track += 1;
312 dmx.tracks.push(track);
313 Ok(size)
314 }
315
316 fn read_moof(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
317 dmx.moof_off = dmx.src.tell() - 8;
318 dmx.read_moof(strmgr, size)?;
319 Ok(size)
320 }
321
322 const MOOF_CHUNK_HANDLERS: &[RootChunkHandler] = &[
323 RootChunkHandler { ctype: mktag!(b"mfhd"), parse: read_mfhd },
324 RootChunkHandler { ctype: mktag!(b"traf"), parse: read_traf },
325 RootChunkHandler { ctype: mktag!(b"meta"), parse: read_meta },
326 ];
327
328 fn read_mfhd(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
329 const KNOWN_MFHD_SIZE: u64 = 8;
330 validate!(size >= KNOWN_MFHD_SIZE);
331 let version = dmx.src.read_byte()?;
332 validate!(version == 0);
333 let flags = dmx.src.read_u24be()?;
334 validate!(flags == 0);
335 let _seq_no = dmx.src.read_u32be()?;
336
337 Ok(KNOWN_MFHD_SIZE)
338 }
339
340 fn read_traf(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
341 let mut buf = [0u8; 16];
342 dmx.src.peek_buf(&mut buf)?;
343 validate!(&buf[4..8] == b"tfhd");
344 let track_id = read_u32be(&buf[12..16])?;
345 let mut track = None;
346 for trk in dmx.tracks.iter_mut() {
347 if trk.track_id == track_id {
348 track = Some(trk);
349 break;
350 }
351 }
352 if let Some(track) = track {
353 track.moof_off = dmx.moof_off;
354 track.read_traf(dmx.src, size)?;
355 Ok(size)
356 } else {
357 Ok(0)
358 }
359 }
360
361 const TRAK_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
362 TrackChunkHandler { ctype: mktag!(b"clip"), parse: skip_chunk },
363 TrackChunkHandler { ctype: mktag!(b"matt"), parse: skip_chunk },
364 TrackChunkHandler { ctype: mktag!(b"edts"), parse: skip_chunk },
365 TrackChunkHandler { ctype: mktag!(b"tref"), parse: skip_chunk },
366 TrackChunkHandler { ctype: mktag!(b"load"), parse: skip_chunk },
367 TrackChunkHandler { ctype: mktag!(b"imap"), parse: skip_chunk },
368 TrackChunkHandler { ctype: mktag!(b"tkhd"), parse: read_tkhd },
369 TrackChunkHandler { ctype: mktag!(b"mdia"), parse: read_mdia },
370 ];
371
372 fn read_tkhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
373 const KNOWN_TKHD_SIZE: u64 = 84;
374 validate!(size >= KNOWN_TKHD_SIZE);
375 let version = br.read_byte()?;
376 validate!(version == 0);
377 let _flags = br.read_u24be()?;
378 let _ctime = br.read_u32be()?;
379 let _mtime = br.read_u32be()?;
380 let track_id = br.read_u32be()?;
381 br.read_skip(4)?;
382 let duration = br.read_u32be()?;
383 br.read_skip(8)?;
384 let _layer = br.read_u16be()?;
385 let _alt_group = br.read_u16be()?;
386 let _volume = br.read_u16be()?;
387 br.read_skip(2)?;
388 br.read_skip(36)?; // matrix
389 let width = br.read_u32be()? as usize;
390 let height = br.read_u32be()? as usize;
391 track.width = width >> 16;
392 track.height = height >> 16;
393 track.track_id = track_id;
394 track.duration = duration;
395
396 track.tkhd_found = true;
397 Ok(KNOWN_TKHD_SIZE)
398 }
399
400 fn read_mdia(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
401 track.stream_type = StreamType::None;
402 track.read_mdia(br, size)?;
403 Ok(size)
404 }
405
406 const MDIA_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
407 TrackChunkHandler { ctype: mktag!(b"mdhd"), parse: read_mdhd },
408 TrackChunkHandler { ctype: mktag!(b"hdlr"), parse: read_hdlr },
409 TrackChunkHandler { ctype: mktag!(b"minf"), parse: read_minf },
410 ];
411
412 fn read_mdhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
413 const KNOWN_MDHD_SIZE: u64 = 24;
414 validate!(size >= KNOWN_MDHD_SIZE);
415 let version = br.read_byte()?;
416 validate!(version == 0);
417 let flags = br.read_u24be()?;
418 validate!(flags == 0);
419 let _ctime = br.read_u32be()?;
420 let _mtime = br.read_u32be()?;
421 track.tb_den = br.read_u32be()?;
422 validate!(track.tb_den != 0);
423 track.duration = br.read_u32be()?;
424 let _language = br.read_u16be()?;
425 let _quality = br.read_u16be()?;
426
427 Ok(KNOWN_MDHD_SIZE)
428 }
429
430 fn read_hdlr(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
431 const KNOWN_HDLR_SIZE: u64 = 24;
432 validate!(size >= KNOWN_HDLR_SIZE);
433 let version = br.read_byte()?;
434 validate!(version == 0);
435 let flags = br.read_u24be()?;
436 validate!(flags == 0);
437 let comp_type = br.read_u32be()?;
438 let comp_subtype = br.read_u32be()?;
439 let _comp_manufacturer = br.read_u32be()?;
440 let _comp_flags = br.read_u32be()?;
441 let _comp_flags_mask = br.read_u32be()?;
442
443 if comp_type == mktag!(b"mhlr") || comp_type == 0 {
444 if comp_subtype == mktag!(b"vide") {
445 track.stream_type = StreamType::Video;
446 } else if comp_subtype == mktag!(b"soun") {
447 track.stream_type = StreamType::Audio;
448 } else {
449 track.stream_type = StreamType::Data;
450 }
451 } else if comp_type == mktag!(b"dhlr") {
452 track.stream_type = StreamType::Data;
453 } else {
454 println!("Unknown stream type");
455 track.stream_type = StreamType::Data;
456 }
457
458 Ok(KNOWN_HDLR_SIZE)
459 }
460
461 fn read_minf(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
462 track.read_minf(br, size)?;
463 Ok(size)
464 }
465
466 const MINF_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
467 TrackChunkHandler { ctype: mktag!(b"hdlr"), parse: skip_chunk },
468 TrackChunkHandler { ctype: mktag!(b"dinf"), parse: skip_chunk },
469 TrackChunkHandler { ctype: mktag!(b"vmhd"), parse: read_vmhd },
470 TrackChunkHandler { ctype: mktag!(b"smhd"), parse: read_smhd },
471 TrackChunkHandler { ctype: mktag!(b"gmhd"), parse: read_gmhd },
472 TrackChunkHandler { ctype: mktag!(b"gmin"), parse: read_gmin },
473 TrackChunkHandler { ctype: mktag!(b"stbl"), parse: read_stbl },
474 ];
475
476 fn read_vmhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
477 const KNOWN_VMHD_SIZE: u64 = 12;
478 validate!(track.stream_type == StreamType::Video);
479 validate!(size >= KNOWN_VMHD_SIZE);
480 let version = br.read_byte()?;
481 validate!(version == 0);
482 let _flags = br.read_u24be()?;
483 br.read_skip(2)?; // graphics mode
484 br.read_skip(6)?; // opcolor
485 Ok(KNOWN_VMHD_SIZE)
486 }
487
488 fn read_smhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
489 const KNOWN_SMHD_SIZE: u64 = 8;
490 validate!(track.stream_type == StreamType::Audio);
491 validate!(size >= KNOWN_SMHD_SIZE);
492 let version = br.read_byte()?;
493 validate!(version == 0);
494 let _flags = br.read_u24be()?;
495 br.read_skip(2)?; // balance
496 br.read_skip(2)?;
497 Ok(KNOWN_SMHD_SIZE)
498 }
499
500 fn read_gmhd(track: &mut Track, _br: &mut ByteReader, _size: u64) -> DemuxerResult<u64> {
501 validate!(track.stream_type == StreamType::Data);
502 Ok(0)
503 }
504
505 fn read_gmin(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
506 validate!(track.stream_type == StreamType::Data);
507 const KNOWN_GMIN_SIZE: u64 = 16;
508 validate!(size >= KNOWN_GMIN_SIZE);
509 let version = br.read_byte()?;
510 validate!(version == 0);
511 let _flags = br.read_u24be()?;
512 br.read_skip(2)?; // graphics mode
513 br.read_skip(6)?; // opcolor
514 br.read_skip(2)?; // balance
515 br.read_skip(2)?;
516 Ok(KNOWN_GMIN_SIZE)
517 }
518
519 fn read_stbl(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
520 track.read_stbl(br, size)?;
521 Ok(size)
522 }
523
524 const STBL_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
525 TrackChunkHandler { ctype: mktag!(b"stsd"), parse: read_stsd },
526 TrackChunkHandler { ctype: mktag!(b"stts"), parse: read_stts },
527 TrackChunkHandler { ctype: mktag!(b"stss"), parse: read_stss },
528 TrackChunkHandler { ctype: mktag!(b"stsc"), parse: read_stsc },
529 TrackChunkHandler { ctype: mktag!(b"stsz"), parse: read_stsz },
530 TrackChunkHandler { ctype: mktag!(b"stco"), parse: read_stco },
531 TrackChunkHandler { ctype: mktag!(b"stsh"), parse: skip_chunk },
532 TrackChunkHandler { ctype: mktag!(b"ctts"), parse: read_ctts },
533 ];
534
535 fn parse_audio_edata(br: &mut ByteReader, start_pos: u64, size: u64) -> DemuxerResult<Option<Vec<u8>>> {
536 let read_part = br.tell() - start_pos;
537 if read_part + 8 < size {
538 let mut buf = [0; 8];
539 br.peek_buf(&mut buf)?;
540 if &buf[4..8] != b"wave" {
541 let mut buf = vec![0; (size - read_part) as usize];
542 br.read_buf(&mut buf)?;
543 return Ok(Some(buf));
544 }
545
546 let csize = br.read_u32be()? as u64;
547 let ctag = br.read_u32be()?;
548 validate!(read_part + csize <= size);
549 validate!(ctag == mktag!(b"wave"));
550 if csize == 8 {
551 return Ok(None);
552 }
553 let mut buf = [0; 8];
554 br.peek_buf(&mut buf)?;
555 if &buf[4..8] == b"frma" {
556 br.read_skip(12)?;
557 if csize > 20 {
558 let mut buf = vec![0; (csize - 20) as usize];
559 br.read_buf(&mut buf)?;
560 Ok(Some(buf))
561 } else {
562 Ok(None)
563 }
564 } else if csize > 8 {
565 let mut buf = vec![0; (csize as usize) - 8];
566 br.read_buf(&mut buf)?;
567 Ok(Some(buf))
568 } else {
569 Ok(None)
570 }
571 } else {
572 Ok(None)
573 }
574 }
575
576 #[allow(clippy::neg_cmp_op_on_partial_ord)]
577 fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
578 const KNOWN_STSD_SIZE: u64 = 24;
579 validate!(size >= KNOWN_STSD_SIZE);
580 let start_pos = br.tell();
581 let version = br.read_byte()?;
582 validate!(version == 0);
583 let _flags = br.read_u24be()?;
584 let entries = br.read_u32be()?;
585 validate!(entries > 0);
586 let esize = u64::from(br.read_u32be()?);
587 validate!(esize + 8 <= size);
588 let mut fcc = [0u8; 4];
589 br.read_buf(&mut fcc)?;
590 br.read_skip(6)?;
591 let _data_ref = br.read_u16be()?;
592
593 track.fcc = fcc;
594
595 let codec_info;
596 match track.stream_type {
597 StreamType::Video => {
598 let _ver = br.read_u16be()?;
599 let _revision = br.read_u16le()?;
600 let _vendor = br.read_u32be()?;
601 let _temp_quality = br.read_u32be()?;
602 let _spat_quality = br.read_u32be()?;
603 let width = br.read_u16be()? as usize;
604 let height = br.read_u16be()? as usize;
605 let _hor_res = br.read_u32be()?;
606 let _vert_res = br.read_u32be()?;
607 let data_size = br.read_u32be()?;
608 validate!(data_size == 0);
609 let _frame_count = br.read_u16be()? as usize;
610 let _cname_len = br.read_byte()? as usize;
611 br.read_skip(31)?; // actual compressor name
612 let depth = br.read_u16be()?;
613 let ctable_id = br.read_u16be()?;
614 let grayscale = depth > 0x20 || depth == 1;
615 let depth = if grayscale { depth & 0x1F } else { depth };
616 if ctable_id == 0 {
617 let max_pal_size = start_pos + size - br.tell();
618 if depth <= 8 {
619 let mut pal = [0; 1024];
620 read_palette(br, max_pal_size, &mut pal)?;
621 track.pal = Some(Arc::new(pal));
622 } else {
623 br.read_skip(max_pal_size as usize)?;
624 }
625 } else if (depth <= 8) && !grayscale {
626 match depth & 0x1F {
627 2 => {
628 let mut pal = [0; 1024];
629 pal[..4 * 4].copy_from_slice(&MOV_DEFAULT_PAL_2BIT);
630 track.pal = Some(Arc::new(pal));
631 },
632 4 => {
633 let mut pal = [0; 1024];
634 pal[..16 * 4].copy_from_slice(&MOV_DEFAULT_PAL_4BIT);
635 track.pal = Some(Arc::new(pal));
636 },
637 8 => {
638 track.pal = Some(Arc::new(MOV_DEFAULT_PAL_8BIT));
639 },
640 _ => {},
641 };
642 } else if grayscale && ctable_id != 0xFFFF {
643 let mut pal = [0; 1024];
644 let cdepth = depth & 0x1F;
645 let size = 1 << cdepth;
646 for i in 0..size {
647 let mut clr = ((size - 1 - i) as u8) << (8 - cdepth);
648 let mut off = 8 - cdepth;
649 while off >= cdepth {
650 clr |= clr >> (8 - off);
651 off -= cdepth;
652 }
653 if off > 0 {
654 clr |= clr >> (8 - off);
655 }
656 pal[i * 4] = clr;
657 pal[i * 4 + 1] = clr;
658 pal[i * 4 + 2] = clr;
659 }
660 track.pal = Some(Arc::new(pal));
661 }
662 // todo other atoms, put as extradata
663 let cname = if let Some(name) = find_codec_from_mov_video_fourcc(&fcc) {
664 name
665 } else if let Some(name) = find_codec_from_avi_fourcc(&fcc) {
666 name
667 } else {
668 "unknown"
669 };
670 let format = if depth > 8 { RGB24_FORMAT } else { PAL8_FORMAT };
671 let mut vhdr = NAVideoInfo::new(width, height, false, format);
672 vhdr.bits = depth as u8;
673 //skip various common atoms
674 while br.tell() - start_pos + 4 < size {
675 let mut buf = [0u8; 8];
676 br.peek_buf(&mut buf)?;
677 let tsize = read_u32be(&buf).unwrap() as usize;
678 let tag = &buf[4..8];
679 validate!(tsize >= 8);
680 match tag {
681 b"pasp" | b"clap" => {
682 br.read_skip(tsize)?;
683 },
684 _ => break,
685 };
686 }
687 let edata = if br.tell() - start_pos + 4 < size {
688 let edata_size = br.read_u32be()? as usize;
689 validate!(edata_size >= 4);
690 let mut buf = vec![0; edata_size - 4];
691 br.read_buf(buf.as_mut_slice())?;
692 Some(buf)
693 } else {
694 None
695 };
696 codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Video(vhdr), edata);
697 },
698 StreamType::Audio => {
699 let sver = br.read_u16be()?;
700 let _revision = br.read_u16le()?;
701 let _vendor = br.read_u32be()?;
702 let mut nchannels = br.read_u16be()?;
703 if sver != 2 {
704 validate!(nchannels <= 64);
705 }
706 let sample_size = br.read_u16be()?;
707 validate!(sample_size <= 128);
708 let _compr_id = br.read_u16be()?;
709 let packet_size = br.read_u16be()? as usize;
710 validate!(packet_size == 0);
711 let mut sample_rate = br.read_u32be()? >> 16;
712 if sver != 2 {
713 validate!(sample_rate > 0);
714 }
715 let cname = if let Some(name) = find_codec_from_mov_audio_fourcc(&fcc) {
716 name
717 } 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]))) {
718 name
719 } else {
720 "unknown"
721 };
722 let mut soniton = NASoniton::new(sample_size as u8, SONITON_FLAG_SIGNED | SONITON_FLAG_BE);
723 if &fcc == b"raw " && sample_size == 8 {
724 soniton.signed = false;
725 }
726 let block_align = 1;
727 match sver {
728 1 => {
729 let samples_per_packet = br.read_u32be()?;
730 let _bytes_per_packet = br.read_u32be()?;
731 let bytes_per_frame = br.read_u32be()?;
732 let _bytes_per_sample = br.read_u32be()?;
733 track.bsize = bytes_per_frame as usize;
734 track.frame_samples = samples_per_packet as usize;
735 track.tb_num = samples_per_packet;
736 },
737 2 => {
738 br.read_u32be()?; // some size
739 let srate = br.read_f64be()?;
740 validate!(srate > 1.0);
741 sample_rate = srate as u32;
742 let channels = br.read_u32be()?;
743 validate!(channels > 0 && channels < 255);
744 nchannels = channels as u16;
745 br.read_u32be()?; // always 0x7F000000
746 let _bits_per_csample = br.read_u32be()?;
747 let _codec_flags = br.read_u32be()?;
748 let bytes_per_frame = br.read_u32be()?;
749 let samples_per_packet = br.read_u32be()?;
750 track.bsize = bytes_per_frame as usize;
751 track.frame_samples = samples_per_packet as usize;
752 track.tb_num = samples_per_packet;
753 },
754 _ => {
755 track.bsize = (sample_size / 8) as usize;
756 },
757 };
758 if track.tb_den <= 1 {
759 track.tb_den = sample_rate;
760 }
761 track.raw_audio = matches!(&fcc,
762 b"NONE" | b"raw " | b"twos" | b"sowt" |
763 b"in24" | b"in32" | b"fl32" | b"fl64" |
764 b"ima4" | b"ms\x00\x02" | b"ms\x00\x21" |
765 b"alaw" | b"ulaw" |
766 b"MAC3" | b"MAC6");
767 let ahdr = NAAudioInfo::new(sample_rate, nchannels as u8, soniton, block_align);
768 let edata = parse_audio_edata(br, start_pos, size)?;
769 codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata);
770 track.channels = nchannels as usize;
771 track.bits = sample_size as usize;
772 },
773 StreamType::None => {
774 return Err(DemuxerError::InvalidData);
775 },
776 _ => {
777 //todo put it all into extradata
778 let edata = None;
779 codec_info = NACodecInfo::new("unknown", NACodecTypeInfo::None, edata);
780 },
781 };
782 let read_size = br.tell() - start_pos;
783 validate!(read_size <= size);
784 track.stream = Some(NAStream::new(track.stream_type, track.track_no, codec_info, track.tb_num, track.tb_den, u64::from(track.duration)));
785 track.stsd_found = true;
786 Ok(read_size)
787 }
788
789 fn read_stts(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
790 validate!(size >= 8);
791 let start_pos = br.tell();
792 let version = br.read_byte()?;
793 validate!(version == 0);
794 let _flags = br.read_u24be()?;
795 let entries = br.read_u32be()? as usize;
796 validate!(entries as u64 <= (size - 8) / 8);
797 if entries == 0 {
798 } else if entries == 1 {
799 let _count = br.read_u32be()?;
800 let tb_num = br.read_u32be()?;
801 validate!(tb_num != 0);
802 track.rescale(tb_num);
803 } else {
804 track.time_to_sample.clear();
805 track.time_to_sample.reserve(entries);
806 for _ in 0..entries {
807 let count = br.read_u32be()?;
808 let mult = br.read_u32be()?;
809 track.time_to_sample.push((count, mult));
810 }
811 }
812 let read_size = br.tell() - start_pos;
813 validate!(read_size <= size);
814 Ok(read_size)
815 }
816
817 fn read_stss(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
818 let version = br.read_byte()?;
819 validate!(version == 0);
820 let _flags = br.read_u24be()?;
821 let entries = br.read_u32be()? as usize;
822 validate!(entries < ((std::u32::MAX >> 2) - 8) as usize);
823 validate!((entries * 4 + 8) as u64 == size);
824 track.keyframes = Vec::with_capacity(entries);
825 let mut last_sample_no = 0;
826 for _ in 0..entries {
827 let sample_no = br.read_u32be()?;
828 validate!(sample_no > last_sample_no);
829 track.keyframes.push(sample_no);
830 last_sample_no = sample_no;
831 }
832 Ok(size)
833 }
834
835 fn read_stsc(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
836 let version = br.read_byte()?;
837 validate!(version == 0);
838 let _flags = br.read_u24be()?;
839 let entries = br.read_u32be()? as usize;
840 validate!(entries < ((std::u32::MAX / 12) - 8) as usize);
841 validate!((entries * 12 + 8) as u64 == size);
842 track.sample_map = Vec::with_capacity(entries);
843 let mut last_sample_no = 0;
844 for _i in 0..entries {
845 let sample_no = br.read_u32be()?;
846 validate!(sample_no > last_sample_no);
847 let nsamples = br.read_u32be()?;
848 let _sample_desc = br.read_u32be()?;
849 track.sample_map.push((sample_no, nsamples));
850 last_sample_no = sample_no;
851 }
852 Ok(size)
853 }
854
855 fn read_stsz(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
856 let version = br.read_byte()?;
857 validate!(version == 0);
858 let _flags = br.read_u24be()?;
859 let sample_size = br.read_u32be()?;
860 if sample_size != 0 {
861 track.sample_size = sample_size;
862 if track.sample_size != 1 || track.bsize == 0 {
863 track.bsize = sample_size as usize;
864 }
865 Ok(8)
866 } else {
867 let entries = br.read_u32be()? as usize;
868 validate!((entries * 4 + 12) as u64 == size);
869 track.chunk_sizes = Vec::with_capacity(entries);
870 for _ in 0..entries {
871 let sample_size = br.read_u32be()?;
872 track.chunk_sizes.push(sample_size);
873 }
874 Ok(size)
875 }
876 }
877
878 fn read_stco(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
879 let version = br.read_byte()?;
880 validate!(version == 0);
881 let _flags = br.read_u24be()?;
882 let entries = br.read_u32be()? as usize;
883 validate!((entries * 4 + 8) as u64 == size);
884 track.chunk_offsets = Vec::with_capacity(entries);
885 for _i in 0..entries {
886 let sample_offset = br.read_u32be()?;
887 track.chunk_offsets.push(u64::from(sample_offset));
888 }
889 Ok(size)
890 }
891
892 fn read_ctts(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
893 validate!(size >= 8);
894 let version = br.read_byte()?;
895 let _flags = br.read_u24be()?;
896 if version > 1 {
897 return Err(DemuxerError::NotImplemented);
898 }
899 let entries = br.read_u32be()? as usize;
900 track.ctts_version = version;
901 track.ctts_map.resize(entries);
902 match version {
903 0 | 1 => {
904 validate!(size == (entries as u64) * 8 + 8);
905 for _ in 0..entries {
906 let samp_count = br.read_u32be()?;
907 let samp_offset = br.read_u32be()?;
908 track.ctts_map.add(samp_count, samp_offset / track.tb_div);
909 }
910 },
911 _ => unreachable!(),
912 };
913 track.ctts_map.reset();
914
915 Ok(size)
916 }
917
918 const TRAF_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
919 TrackChunkHandler { ctype: mktag!(b"tfhd"), parse: read_tfhd },
920 TrackChunkHandler { ctype: mktag!(b"trun"), parse: read_trun },
921 TrackChunkHandler { ctype: mktag!(b"sbgp"), parse: skip_chunk },
922 TrackChunkHandler { ctype: mktag!(b"sgpd"), parse: skip_chunk },
923 TrackChunkHandler { ctype: mktag!(b"subs"), parse: skip_chunk },
924 TrackChunkHandler { ctype: mktag!(b"saiz"), parse: skip_chunk },
925 TrackChunkHandler { ctype: mktag!(b"saio"), parse: skip_chunk },
926 TrackChunkHandler { ctype: mktag!(b"tfdt"), parse: skip_chunk },
927 TrackChunkHandler { ctype: mktag!(b"meta"), parse: skip_chunk },
928 ];
929
930 fn read_tfhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
931 validate!(size >= 8);
932 let start = br.tell();
933 let _version = br.read_byte()?;
934 let flags = br.read_u24be()?;
935 let _track_id = br.read_u32be()?;
936 if (flags & 0x000001) != 0 {
937 let base_offset = br.read_u64be()?;
938 track.moof_off = base_offset;
939 }
940 if (flags & 0x000002) != 0 {
941 let _sample_description_index = br.read_u32be()?;
942 }
943 if (flags & 0x000008) != 0 {
944 let default_sample_duration = br.read_u32be()?;
945 if track.tb_div == 1 {
946 track.rescale(default_sample_duration);
947 }
948 }
949 if (flags & 0x000010) != 0 {
950 let _default_sample_size = br.read_u32be()?;
951 }
952 if (flags & 0x000020) != 0 {
953 let _default_sample_flags = br.read_u32be()?;
954 }
955 if (flags & 0x010000) != 0 {
956 }
957 /*if (flags & 0x020000) != 0 { // base offset is moof start
958 }*/
959 Ok(br.tell() - start)
960 }
961
962 fn read_trun(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
963 validate!(size >= 8);
964 let version = br.read_byte()?;
965 let flags = br.read_u24be()?;
966 let data_off_present = (flags & 0x000001) != 0;
967 let first_sample_flags = (flags & 0x000004) != 0;
968 let sample_duration_present = (flags & 0x000100) != 0;
969 let sample_size_present = (flags & 0x000200) != 0;
970 let sample_flags_present = (flags & 0x000400) != 0;
971 let sample_ct_off_present = (flags & 0x000800) != 0;
972
973 let sample_count = br.read_u32be()? as usize;
974
975 let mut hdr_size = 8;
976 let mut arr_size = 0;
977 if data_off_present {
978 hdr_size += 4;
979 }
980 if first_sample_flags {
981 hdr_size += 4;
982 }
983 if sample_duration_present {
984 arr_size += 4;
985 }
986 if sample_size_present {
987 arr_size += 4;
988 }
989 if sample_flags_present {
990 arr_size += 4;
991 }
992 if sample_ct_off_present {
993 arr_size += 4;
994 }
995 validate!(size == hdr_size + arr_size * (sample_count as u64));
996
997 let mut data_off = if data_off_present {
998 let off = br.read_u32be()? as i32;
999 let new_off = (track.moof_off as i64) + i64::from(off);
1000 validate!(new_off > 0);
1001 new_off as u64
1002 } else {
1003 track.moof_off
1004 };
1005 if first_sample_flags {
1006 let _flags = br.read_u32be()?;
1007 }
1008
1009 if sample_size_present {
1010 track.chunk_sizes.reserve(sample_count);
1011 track.chunk_offsets.reserve(sample_count);
1012 }
1013
1014 if sample_ct_off_present {
1015 if track.ctts_version != version {
1016 track.ctts_version = version;
1017 }
1018 track.ctts_map.reserve(sample_count);
1019 }
1020
1021 if track.chunk_offsets.len() < (std::u32::MAX as usize) {
1022 track.keyframes.push((track.chunk_offsets.len() + 1) as u32);
1023 }
1024 for _ in 0..sample_count {
1025 if sample_duration_present {
1026 let _duration = br.read_u32be()?;
1027 }
1028 if sample_size_present {
1029 let ssize = br.read_u32be()?;
1030 track.chunk_sizes.push(ssize);
1031 track.chunk_offsets.push(data_off);
1032 data_off += u64::from(ssize);
1033 }
1034 if sample_flags_present {
1035 let _flags = br.read_u32be()?;
1036 }
1037 if sample_ct_off_present {
1038 let samp_offset = br.read_u32be()?;
1039 if version == 0 {
1040 track.ctts_map.add(1, samp_offset / track.tb_div);
1041 } else {
1042 track.ctts_map.add(1, ((samp_offset as i32) / (track.tb_div as i32)) as u32);
1043 }
1044 }
1045 }
1046
1047 Ok(size)
1048 }
1049
1050 struct MOVDemuxer<'a> {
1051 src: &'a mut ByteReader<'a>,
1052 depth: usize,
1053 mdat_pos: u64,
1054 mdat_size: u64,
1055 tracks: Vec<Track>,
1056 cur_track: usize,
1057 tb_den: u32,
1058 duration: u32,
1059 pal: Option<Arc<[u8; 1024]>>,
1060
1061 moof_off: u64,
1062
1063 print_chunks: bool,
1064
1065 macbinary: bool,
1066 }
1067
1068 struct Track {
1069 track_id: u32,
1070 track_str_id: usize,
1071 track_no: u32,
1072 tb_num: u32,
1073 tb_den: u32,
1074 tb_div: u32,
1075 raw_audio: bool,
1076 raw_apos: u64,
1077 duration: u32,
1078 depth: u8,
1079 tkhd_found: bool,
1080 stsd_found: bool,
1081 stream_type: StreamType,
1082 width: usize,
1083 height: usize,
1084 channels: usize,
1085 bits: usize,
1086 bsize: usize,
1087 fcc: [u8; 4],
1088 keyframes: Vec<u32>,
1089 chunk_sizes: Vec<u32>,
1090 chunk_offsets: Vec<u64>,
1091 time_to_sample: Vec<(u32, u32)>,
1092 sample_map: Vec<(u32, u32)>,
1093 sample_size: u32,
1094 frame_samples: usize,
1095 ctts_map: RLESearcher<u32>,
1096 ctts_version: u8,
1097 stream: Option<NAStream>,
1098 cur_chunk: usize,
1099 cur_sample: usize,
1100 cur_ts: Option<u64>,
1101 samples_left: usize,
1102 last_offset: u64,
1103 pal: Option<Arc<[u8; 1024]>>,
1104 timesearch: TimeSearcher,
1105
1106 moof_off: u64,
1107
1108 print_chunks: bool,
1109 }
1110
1111 #[derive(Default)]
1112 struct TimeSearcher {
1113 idx: usize,
1114 base: u64,
1115 sbase: u32,
1116 cur_len: u32,
1117 cur_mul: u32,
1118 }
1119
1120 impl TimeSearcher {
1121 fn new() -> Self { Self::default() }
1122 fn reset(&mut self) {
1123 *self = Self::default();
1124 }
1125 fn map_time(&mut self, sample: u32, tts: &[(u32, u32)]) -> u64 {
1126 if tts.is_empty() {
1127 u64::from(sample)
1128 } else if sample >= self.sbase {
1129 let mut sample = sample - self.sbase;
1130 if self.idx == 0 {
1131 let (cur_len, cur_mul) = tts[0];
1132 self.cur_len = cur_len;
1133 self.cur_mul = cur_mul;
1134 self.idx += 1;
1135 }
1136 while self.idx < tts.len() && sample > self.cur_len {
1137 sample -= self.cur_len;
1138 self.sbase += self.cur_len;
1139 self.base += u64::from(self.cur_len) * u64::from(self.cur_mul);
1140 self.cur_len = tts[self.idx].0;
1141 self.cur_mul = tts[self.idx].1;
1142 self.idx += 1;
1143 }
1144 self.base + u64::from(sample) * u64::from(self.cur_mul)
1145 } else {
1146 self.reset();
1147 self.map_time(sample, tts)
1148 }
1149 }
1150 }
1151
1152 #[derive(Default)]
1153 struct RLESearcher<T> {
1154 array: Vec<(u32, T)>,
1155 idx: usize,
1156 start: u64,
1157 next: u64,
1158 }
1159
1160 impl<T:Default+Copy> RLESearcher<T> {
1161 fn new() -> Self { Self::default() }
1162 fn resize(&mut self, size: usize) {
1163 self.array.clear();
1164 self.array.reserve(size);
1165 }
1166 fn reserve(&mut self, size: usize) {
1167 self.array.reserve(size);
1168 }
1169 fn add(&mut self, len: u32, val: T) {
1170 self.array.push((len, val));
1171 }
1172 fn reset(&mut self) {
1173 self.start = 0;
1174 if !self.array.is_empty() {
1175 self.idx = 0;
1176 self.next = u64::from(self.array[0].0);
1177 } else {
1178 self.idx = self.array.len();
1179 self.next = 0;
1180 }
1181 }
1182 fn map(&mut self, sample: u64) -> Option<T> {
1183 if sample < self.start {
1184 self.reset();
1185 }
1186 if self.idx < self.array.len() {
1187 if sample < self.next {
1188 Some(self.array[self.idx].1)
1189 } else {
1190 while (self.idx < self.array.len()) && (sample >= self.next) {
1191 self.start = self.next;
1192 self.idx += 1;
1193 if self.idx < self.array.len() {
1194 self.next += u64::from(self.array[self.idx].0);
1195 }
1196 }
1197 if self.idx < self.array.len() {
1198 Some(self.array[self.idx].1)
1199 } else {
1200 None
1201 }
1202 }
1203 } else {
1204 None
1205 }
1206 }
1207 }
1208
1209 impl Track {
1210 fn new(track_no: u32, tb_den: u32) -> Self {
1211 Self {
1212 tkhd_found: false,
1213 stsd_found: false,
1214 track_id: 0,
1215 track_str_id: 0,
1216 track_no,
1217 tb_num: 1,
1218 tb_den,
1219 tb_div: 1,
1220 raw_audio: false,
1221 raw_apos: 0,
1222 duration: 0,
1223 stream_type: StreamType::None,
1224 width: 0,
1225 height: 0,
1226 channels: 0,
1227 bits: 0,
1228 bsize: 0,
1229 fcc: [0; 4],
1230 keyframes: Vec::new(),
1231 chunk_sizes: Vec::new(),
1232 chunk_offsets: Vec::new(),
1233 time_to_sample: Vec::new(),
1234 sample_map: Vec::new(),
1235 sample_size: 0,
1236 frame_samples: 0,
1237 ctts_map: RLESearcher::new(),
1238 ctts_version: 0,
1239 stream: None,
1240 depth: 0,
1241 cur_chunk: 0,
1242 cur_sample: 0,
1243 cur_ts: None,
1244 samples_left: 0,
1245 last_offset: 0,
1246 pal: None,
1247 timesearch: TimeSearcher::new(),
1248
1249 moof_off: 0,
1250
1251 print_chunks: false,
1252 }
1253 }
1254 read_chunk_list!(track; "trak", read_trak, TRAK_CHUNK_HANDLERS);
1255 read_chunk_list!(track; "mdia", read_mdia, MDIA_CHUNK_HANDLERS);
1256 read_chunk_list!(track; "minf", read_minf, MINF_CHUNK_HANDLERS);
1257 read_chunk_list!(track; "stbl", read_stbl, STBL_CHUNK_HANDLERS);
1258 read_chunk_list!(track; "traf", read_traf, TRAF_CHUNK_HANDLERS);
1259 fn rescale(&mut self, tb_num: u32) {
1260 self.tb_div = tb_num;
1261 if let Some(ref mut stream) = self.stream {
1262 let tb_den = stream.tb_den;
1263 let (tb_num, tb_den) = reduce_timebase(tb_num * stream.tb_num, tb_den);
1264 stream.duration /= u64::from(self.tb_div);
1265 stream.tb_num = tb_num;
1266 stream.tb_den = tb_den;
1267 self.tb_num = tb_num;
1268 self.tb_den = tb_den;
1269 self.duration /= self.tb_div;
1270 }
1271 }
1272 fn fill_seek_index(&self, seek_index: &mut SeekIndex) {
1273 if !self.keyframes.is_empty() {
1274 seek_index.mode = SeekIndexMode::Present;
1275 }
1276 let mut tsearch = TimeSearcher::new();
1277 for kf_time in self.keyframes.iter() {
1278 let pts = tsearch.map_time(*kf_time - 1, &self.time_to_sample);
1279 let time = NATimeInfo::ts_to_time(pts, 1000, self.tb_num, self.tb_den);
1280 seek_index.add_entry(self.track_no, SeekEntry { time, pts: u64::from(*kf_time - 1), pos: 0 });
1281 }
1282 }
1283 fn calculate_chunk_size(&self, nsamp: usize) -> usize {
1284 if nsamp == 0 {
1285 self.bsize
1286 } else {
1287 match &self.fcc {
1288 b"NONE" | b"raw " | b"twos" | b"sowt" => {
1289 (nsamp * self.bits * self.channels + 7) >> 3
1290 },
1291 b"ima4" => {
1292 let nblocks = (nsamp + 63) >> 6;
1293 nblocks * 34 * self.channels
1294 },
1295 b"MAC3" => {
1296 (nsamp + 5) / 6 * 2 * self.channels
1297 },
1298 b"MAC6" => {
1299 (nsamp + 5) / 6 * self.channels
1300 },
1301 b"in24" => nsamp * 3 * self.channels,
1302 b"in32" | b"fl32" => nsamp * 4 * self.channels,
1303 b"fl64" => nsamp * 8 * self.channels,
1304 b"ulaw" | b"alaw" => nsamp,
1305 b"ms\x00\x02" => { //MS ADPCM
1306 ((nsamp - 1) / 2 + 7) * self.channels
1307 },
1308 b"ms\x00\x21" => { //IMA ADPCM
1309 (nsamp / 2 + 4) * self.channels
1310 },
1311 _ => self.bsize,
1312 }
1313 }
1314 }
1315 fn get_next_chunk(&mut self) -> Option<(NATimeInfo, u64, usize)> {
1316 let pts_val = self.timesearch.map_time(self.cur_sample as u32, &self.time_to_sample);
1317 let dts = if let Some(dts_corr) = self.ctts_map.map(self.cur_sample as u64) {
1318 let dts = match self.ctts_version {
1319 0 => pts_val.wrapping_add(u64::from(dts_corr)),
1320 1 => pts_val.wrapping_add(i64::from(dts_corr as i32) as u64),
1321 _ => unimplemented!(),
1322 };
1323 if (dts as i64) < 0 {
1324 None
1325 } else {
1326 Some(dts)
1327 }
1328 } else {
1329 Some(pts_val)
1330 };
1331 let mut pts = NATimeInfo::new(Some(pts_val), dts, None, self.tb_num, self.tb_den);
1332 if self.chunk_offsets.len() == self.chunk_sizes.len() { // simple one-to-one mapping
1333 if self.cur_sample >= self.chunk_sizes.len() {
1334 return None;
1335 }
1336 let offset = self.chunk_offsets[self.cur_sample];
1337 let size = self.chunk_sizes[self.cur_sample] as usize;
1338 self.cur_sample += 1;
1339 Some((pts, offset, size))
1340 } else {
1341 if self.samples_left == 0 {
1342 if self.cur_chunk >= self.chunk_offsets.len() {
1343 return None;
1344 }
1345 for (idx, samples) in self.sample_map.iter() {
1346 if *idx as usize <= self.cur_chunk + 1 {
1347 self.samples_left = *samples as usize;
1348 } else {
1349 break;
1350 }
1351 }
1352 self.last_offset = self.chunk_offsets[self.cur_chunk];
1353 self.cur_chunk += 1;
1354 }
1355 let offset = self.last_offset;
1356 let size = self.get_size(self.cur_sample);
1357 self.last_offset += size as u64;
1358 if self.stream_type == StreamType::Video {
1359 self.samples_left -= 1;
1360 } else if self.frame_samples != 0 && self.bsize != 0 {
1361 let nblocks = size / self.bsize;
1362 if self.raw_audio {
1363 pts.pts = Some(self.raw_apos);
1364 pts.duration = Some(nblocks as u64);
1365 self.raw_apos += nblocks as u64;
1366 }
1367 if nblocks > 0 {
1368 let consumed = (nblocks * self.frame_samples).min(self.samples_left);
1369 self.samples_left -= consumed;
1370 } else {
1371 self.samples_left = 0;
1372 }
1373 } else if !self.raw_audio {
1374 self.samples_left -= 1;
1375 } else {
1376 const BLOCK_SAMPLES: usize = 1024 * 6; // should be multiple of 64 and 6 to fit both IMA ADPCM and MACE 6:1 blocks
1377 let max_size = self.calculate_chunk_size(BLOCK_SAMPLES);
1378 let cur_size = self.calculate_chunk_size(self.samples_left);
1379 let add_off = (size - cur_size) as u64;
1380 let dsize = cur_size.min(max_size);
1381 if self.samples_left >= BLOCK_SAMPLES {
1382 self.cur_sample += BLOCK_SAMPLES;
1383 self.samples_left -= BLOCK_SAMPLES;
1384 self.last_offset -= size as u64;
1385 } else {
1386 self.cur_sample += self.samples_left;
1387 self.samples_left = 0;
1388 }
1389 return Some((pts, offset + add_off, dsize));
1390 }
1391 self.cur_sample += 1;
1392 Some((pts, offset, size))
1393 }
1394 }
1395 fn get_size(&self, sample_no: usize) -> usize {
1396 if !self.chunk_sizes.is_empty() {
1397 self.chunk_sizes[sample_no] as usize
1398 } else if !self.sample_map.is_empty() {
1399 let mut nsamp = 0;
1400 for (idx, samples) in self.sample_map.iter() {
1401 if *idx as usize <= self.cur_chunk {
1402 nsamp = *samples;
1403 } else {
1404 break;
1405 }
1406 }
1407 self.calculate_chunk_size(nsamp as usize)
1408 } else {
1409 self.bsize
1410 }
1411 }
1412 #[allow(clippy::collapsible_if)]
1413 #[allow(clippy::collapsible_else_if)]
1414 fn seek(&mut self, pts: u64, tpoint: NATimePoint) -> DemuxerResult<u64> {
1415 self.cur_sample = pts as usize;
1416 self.samples_left = 0;
1417 self.cur_ts = None;
1418 if self.stream_type == StreamType::Audio {
1419 if let NATimePoint::Milliseconds(ms) = tpoint {
1420 let exp_pts = NATimeInfo::time_to_ts(ms, 1000, self.tb_num, self.tb_den);
1421 if self.raw_audio {
1422 if self.frame_samples != 0 {
1423 self.raw_apos = exp_pts / (self.frame_samples as u64);
1424 let mut apos = 0;
1425 self.cur_sample = 0;
1426 self.cur_chunk = 0;
1427 let mut cmap = self.sample_map.iter();
1428 let mut cur_samps = 0;
1429 let (mut next_idx, mut next_samples) = cmap.next().unwrap();
1430 loop {
1431 if self.cur_chunk + 1 == next_idx as usize {
1432 self.samples_left = cur_samps;
1433 cur_samps = next_samples as usize;
1434 if let Some((new_idx, new_samples)) = cmap.next() {
1435 next_idx = *new_idx;
1436 next_samples = *new_samples;
1437 }
1438 }
1439 self.raw_apos = apos;
1440 apos += (cur_samps / self.frame_samples) as u64;
1441 if apos > exp_pts {
1442 if cur_samps == self.frame_samples || apos > exp_pts + 1 {
1443 if self.cur_chunk >= self.chunk_offsets.len() {
1444 return Err(DemuxerError::SeekError);
1445 }
1446 self.last_offset = self.chunk_offsets[self.cur_chunk];
1447 break;
1448 }
1449 }
1450 self.cur_chunk += 1;
1451 }
1452 self.samples_left = cur_samps;
1453 self.cur_chunk += 1;
1454 } else {
1455 self.raw_apos = exp_pts;
1456 self.cur_sample = exp_pts as usize;
1457 let mut csamp = 0;
1458 self.cur_chunk = 0;
1459 let mut cmap = self.sample_map.iter();
1460 let mut cur_samps = 0;
1461 let (mut next_idx, mut next_samples) = cmap.next().unwrap();
1462 loop {
1463 if self.cur_chunk + 1 == next_idx as usize {
1464 self.samples_left = cur_samps;
1465 cur_samps = next_samples as usize;
1466 if let Some((new_idx, new_samples)) = cmap.next() {
1467 next_idx = *new_idx;
1468 next_samples = *new_samples;
1469 }
1470 }
1471 csamp += cur_samps;
1472 if csamp > self.cur_sample {
1473 if self.cur_chunk >= self.chunk_offsets.len() {
1474 return Err(DemuxerError::SeekError);
1475 }
1476 self.last_offset = self.chunk_offsets[self.cur_chunk];
1477 break;
1478 }
1479 self.cur_chunk += 1;
1480 }
1481 self.samples_left = csamp - self.cur_sample;
1482 self.cur_chunk += 1;
1483 }
1484 } else if self.chunk_offsets.len() == self.chunk_sizes.len() {
1485 self.cur_chunk = self.cur_sample;
1486 } else {
1487 if !self.time_to_sample.is_empty() {
1488 let mut remaining = exp_pts;
1489 let mut abs_csamp = 0;
1490 for &(count, scount) in self.time_to_sample.iter() {
1491 let count = u64::from(count);
1492 let scount = u64::from(scount);
1493 let nblk = remaining / scount;
1494 if nblk < count {
1495 abs_csamp += nblk;
1496 break;
1497 }
1498 remaining -= count * scount;
1499 abs_csamp += count;
1500 }
1501 self.cur_sample = abs_csamp as usize;
1502 } else {
1503 self.cur_sample = exp_pts as usize;
1504 }
1505 let tgt_sample = self.cur_sample;
1506 let mut csamp = 0;
1507 self.cur_chunk = 0;
1508 let mut cmap = self.sample_map.iter();
1509 let mut cur_samps = 0;
1510 let (mut next_idx, mut next_samples) = cmap.next().unwrap();
1511 loop {
1512 if self.cur_chunk + 1 == next_idx as usize {
1513 self.samples_left = cur_samps;
1514 cur_samps = next_samples as usize;
1515 if let Some((new_idx, new_samples)) = cmap.next() {
1516 next_idx = *new_idx;
1517 next_samples = *new_samples;
1518 }
1519 }
1520 csamp += cur_samps;
1521 if csamp > self.cur_sample {
1522 if self.cur_chunk >= self.chunk_offsets.len() {
1523 self.cur_sample = csamp - cur_samps;
1524 self.samples_left = 0;
1525 self.cur_sample = csamp;
1526 return Err(DemuxerError::SeekError);
1527 }
1528 self.last_offset = self.chunk_offsets[self.cur_chunk];
1529 break;
1530 }
1531 self.cur_chunk += 1;
1532 }
1533 self.cur_sample = csamp - cur_samps;
1534 self.samples_left = cur_samps;
1535 self.last_offset = self.chunk_offsets[self.cur_chunk];
1536 self.cur_chunk += 1;
1537
1538 // try to refine sample position
1539 if self.chunk_sizes.len() > self.chunk_offsets.len() {
1540 for i in self.cur_sample..tgt_sample {
1541 self.cur_sample += 1;
1542 self.samples_left -= 1;
1543 self.last_offset += u64::from(self.chunk_sizes[i]);
1544 }
1545 }
1546 }
1547 } else {
1548 self.cur_chunk = self.cur_sample;
1549 }
1550 } else if self.chunk_offsets.len() != self.chunk_sizes.len() && !self.sample_map.is_empty() {
1551 let mut csamp = 0;
1552 self.cur_chunk = 0;
1553 let mut cmap = self.sample_map.iter();
1554 let mut cur_samps = 0;
1555 let (mut next_idx, mut next_samples) = cmap.next().unwrap();
1556 loop {
1557 if self.cur_chunk + 1 == next_idx as usize {
1558 self.samples_left = cur_samps;
1559 cur_samps = next_samples as usize;
1560 if let Some((new_idx, new_samples)) = cmap.next() {
1561 next_idx = *new_idx;
1562 next_samples = *new_samples;
1563 }
1564 }
1565 csamp += cur_samps;
1566 if csamp >= self.cur_sample {
1567 if self.cur_chunk >= self.chunk_offsets.len() {
1568 return Err(DemuxerError::SeekError);
1569 }
1570 self.last_offset = self.chunk_offsets[self.cur_chunk];
1571 break;
1572 }
1573 self.cur_chunk += 1;
1574 }
1575 csamp -= cur_samps;
1576 for sample_no in csamp..self.cur_sample {
1577 self.last_offset += self.get_size(sample_no) as u64;
1578 }
1579 self.samples_left = csamp + cur_samps - self.cur_sample;
1580 self.cur_chunk += 1;
1581 }
1582 let cur_pts = self.timesearch.map_time(self.cur_sample as u32, &self.time_to_sample);
1583 let cur_time = NATimeInfo::ts_to_time(cur_pts, 1000, self.tb_num, self.tb_den);
1584 Ok(cur_time)
1585 }
1586 }
1587
1588 fn process_packet(src: &mut ByteReader, strmgr: &StreamManager, track: &mut Track, pts: NATimeInfo, offset: u64, size: usize, first: bool) -> DemuxerResult<NAPacket> {
1589 if let Some(cpts) = pts.get_pts() {
1590 let ts = NATimeInfo::ts_to_time(cpts, 1000, pts.tb_num, pts.tb_den);
1591 track.cur_ts = Some(ts);
1592 } else {
1593 track.cur_ts = None;
1594 }
1595 let stream = strmgr.get_stream(track.track_str_id);
1596 if stream.is_none() { return Err(DemuxerError::InvalidData); }
1597 let stream = stream.unwrap();
1598 src.seek(SeekFrom::Start(offset))?;
1599 let mut pkt = src.read_packet(stream, pts, false, size)?;
1600 if let Some(ref pal) = track.pal {
1601 let side_data = NASideData::Palette(first, pal.clone());
1602 pkt.add_side_data(side_data);
1603 }
1604 Ok(pkt)
1605 }
1606
1607 impl<'a> DemuxCore<'a> for MOVDemuxer<'a> {
1608 fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
1609 if !self.macbinary {
1610 self.read_root(strmgr)?;
1611 } else {
1612 let ver = self.src.read_byte()?;
1613 validate!(ver == 0);
1614 self.src.read_skip(64)?;
1615 let tag = self.src.read_tag()?;
1616 validate!(&tag == b"MooV");
1617 self.src.read_skip(14)?;
1618 let data_length = self.src.read_u32be()?;
1619 validate!(data_length > 8);
1620 let rsrc_length = self.src.read_u32be()?;
1621 validate!(rsrc_length > 0);
1622 self.src.read_skip(31)?;
1623 let ver = self.src.read_byte()?;
1624 validate!(ver == 0x81);
1625 let ver = self.src.read_byte()?;
1626 validate!(ver == 0x81);
1627 //xxx: maybe check header CRC
1628
1629 let rsrc_start = 0x80 + ((data_length + 0x7F) & !0x7F);
1630 self.src.seek(SeekFrom::Start(rsrc_start.into()))?;
1631 let rsrc_off = self.src.read_u32be()?;
1632 let rsrc_map_off = self.src.read_u32be()?;
1633 let rsrc_size = self.src.read_u32be()?;
1634 let _rsrc_map_size = self.src.read_u32be()?;
1635 validate!(rsrc_off >= 0x10);
1636 validate!(rsrc_map_off >= rsrc_off + rsrc_size);
1637 self.src.seek(SeekFrom::Current(i64::from(rsrc_off - 16)))?;
1638 // I'm too lazy to parse resource map, so let's just iterate over resources for movie header
1639 let end_pos = u64::from(rsrc_start + rsrc_off + rsrc_size);
1640 let mut peek_buf = [0u8; 8];
1641 while self.src.tell() < end_pos {
1642 let cur_size = self.src.read_u32be()?;
1643 validate!(self.src.tell() + u64::from(cur_size) <= end_pos);
1644 if cur_size > 8 {
1645 let rsize = self.src.peek_u32be()?;
1646 if rsize == cur_size {
1647 self.src.peek_buf(&mut peek_buf)?;
1648 if &peek_buf[4..] == b"moov" {
1649 self.src.read_skip(8)?;
1650 self.read_moov(strmgr, rsize.into())?;
1651 self.mdat_pos = 8;
1652 break;
1653 }
1654 }
1655 }
1656 self.src.read_skip(cur_size as usize)?;
1657 }
1658 }
1659 validate!(self.mdat_pos > 0);
1660 validate!(!self.tracks.is_empty());
1661 for track in self.tracks.iter_mut() {
1662 let mut strm = None;
1663 std::mem::swap(&mut track.stream, &mut strm);
1664 if let Some(stream) = strm {
1665 let str_id = strmgr.add_stream(stream).unwrap();
1666 track.track_str_id = str_id;
1667 }
1668 }
1669 if self.macbinary {
1670 // patch data offsets
1671 for track in self.tracks.iter_mut() {
1672 for offset in track.chunk_offsets.iter_mut() {
1673 *offset += 0x80;
1674 }
1675 }
1676 }
1677 for track in self.tracks.iter() {
1678 track.fill_seek_index(seek_index);
1679 }
1680 self.src.seek(SeekFrom::Start(self.mdat_pos))?;
1681 self.cur_track = 0;
1682 Ok(())
1683 }
1684
1685 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
1686 if self.tracks.is_empty() {
1687 return Err(DemuxerError::EOF);
1688 }
1689 let mut has_all_time = true;
1690 let mut min_ts = std::u64::MAX;
1691 for trk in self.tracks.iter() {
1692 if let Some(ts) = trk.cur_ts {
1693 min_ts = min_ts.min(ts);
1694 } else {
1695 has_all_time = false;
1696 break;
1697 }
1698 }
1699 if has_all_time {
1700 for (trk_no, track) in self.tracks.iter_mut().enumerate() {
1701 if let Some(ts) = track.cur_ts {
1702 if ts == min_ts {
1703 let first = track.cur_sample == 0;
1704 if let Some((pts, offset, size)) = track.get_next_chunk() {
1705 self.cur_track = trk_no + 1;
1706 return process_packet(self.src, strmgr, track, pts, offset, size, first);
1707 }
1708 }
1709 }
1710 }
1711 }
1712
1713 for _ in 0..self.tracks.len() {
1714 if self.cur_track >= self.tracks.len() {
1715 self.cur_track = 0;
1716 }
1717 let track = &mut self.tracks[self.cur_track];
1718 self.cur_track += 1;
1719 let first = track.cur_sample == 0;
1720 if let Some((pts, offset, size)) = track.get_next_chunk() {
1721 return process_packet(self.src, strmgr, track, pts, offset, size, first);
1722 }
1723 }
1724 Err(DemuxerError::EOF)
1725 }
1726
1727 fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
1728 let ret = seek_index.find_pos(time);
1729 if ret.is_none() {
1730 if let NATimePoint::Milliseconds(_) = time {
1731 let mut aonly = true;
1732 for track in self.tracks.iter() {
1733 if track.stream_type != StreamType::Audio {
1734 aonly = false;
1735 break;
1736 }
1737 }
1738 if aonly {
1739 for track in self.tracks.iter_mut() {
1740 track.seek(0, time)?;
1741 }
1742 return Ok(());
1743 }
1744 }
1745 return Err(DemuxerError::SeekError);
1746 }
1747 let seek_info = ret.unwrap();
1748 let tbn = self.tracks[seek_info.str_id as usize].tb_num;
1749 let tbd = self.tracks[seek_info.str_id as usize].tb_den;
1750 let mut vpts = None;
1751 let mut apts = None;
1752 for track in self.tracks.iter_mut() {
1753 let cur_pts = if track.track_id == seek_info.str_id {
1754 seek_info.pts
1755 } else {
1756 seek_info.pts * u64::from(tbn) * u64::from(track.tb_den) / (u64::from(tbd) * u64::from(track.tb_num))
1757 };
1758 let actual_time = track.seek(cur_pts, time)?;
1759 match track.stream_type {
1760 StreamType::Video => vpts = Some(actual_time),
1761 StreamType::Audio => apts = Some(actual_time),
1762 _ => {},
1763 };
1764 }
1765 /* For audio+video stream case when the post-seek actual times differ
1766 by more than half a second try to seek audio to a closer position
1767 to video.
1768 */
1769 if let (true, Some(vtime), Some(atime)) = (self.tracks.len() == 2, vpts, apts) {
1770 if vtime.max(atime) - vtime.min(atime) > 500 && atime != 0 {
1771 for track in self.tracks.iter_mut() {
1772 if track.stream_type == StreamType::Audio {
1773 let new_pts = NATimeInfo::time_to_ts(vtime, 1000, track.tb_num, track.tb_den);
1774 track.seek(new_pts, NATimePoint::Milliseconds(vtime))?;
1775 }
1776 }
1777 }
1778 }
1779
1780 Ok(())
1781 }
1782 fn get_duration(&self) -> u64 {
1783 if self.tb_den != 0 {
1784 u64::from(self.duration) * 1000 / u64::from(self.tb_den)
1785 } else {
1786 0
1787 }
1788 }
1789 }
1790
1791 const PRINT_CHUNKS: &str = "print_chunks";
1792
1793 const DEMUXER_OPTIONS: &[NAOptionDefinition] = &[
1794 NAOptionDefinition {
1795 name: PRINT_CHUNKS,
1796 description: "Print parsed file structure",
1797 opt_type: NAOptionDefinitionType::Bool },
1798 ];
1799
1800 impl<'a> NAOptionHandler for MOVDemuxer<'a> {
1801 fn get_supported_options(&self) -> &[NAOptionDefinition] { DEMUXER_OPTIONS }
1802 #[allow(clippy::single_match)]
1803 fn set_options(&mut self, options: &[NAOption]) {
1804 for option in options.iter() {
1805 for opt_def in DEMUXER_OPTIONS.iter() {
1806 if opt_def.check(option).is_ok() {
1807 match (option.name, &option.value) {
1808 (PRINT_CHUNKS, NAValue::Bool(val)) => {
1809 self.print_chunks = *val;
1810 },
1811 _ => {},
1812 }
1813 }
1814 }
1815 }
1816 }
1817 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1818 match name {
1819 PRINT_CHUNKS => Some(NAValue::Bool(self.print_chunks)),
1820 _ => None,
1821 }
1822 }
1823 }
1824
1825 impl<'a> MOVDemuxer<'a> {
1826 fn new(io: &'a mut ByteReader<'a>) -> Self {
1827 Self::new_common(io, false)
1828 }
1829 fn new_macbinary(io: &'a mut ByteReader<'a>) -> Self {
1830 Self::new_common(io, true)
1831 }
1832 fn new_common(io: &'a mut ByteReader<'a>, macbinary: bool) -> Self {
1833 MOVDemuxer {
1834 src: io,
1835 depth: 0,
1836 mdat_pos: 0,
1837 mdat_size: 0,
1838 tracks: Vec::with_capacity(2),
1839 cur_track: 0,
1840 tb_den: 0,
1841 duration: 0,
1842 pal: None,
1843
1844 moof_off: 0,
1845
1846 print_chunks: false,
1847
1848 macbinary,
1849 }
1850 }
1851 fn read_root(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
1852 self.depth = 0;
1853 while self.src.left() != 0 {
1854 let ret = read_chunk_header(self.src);
1855 if ret.is_err() { break; }
1856 let (ctype, size) = ret.unwrap();
1857 if self.print_chunks {
1858 print_cname(ctype, size, self.src.tell(), 0);
1859 }
1860 if IGNORED_CHUNKS.contains(&ctype) {
1861 self.src.skip64(size)?;
1862 continue;
1863 }
1864 let handler = ROOT_CHUNK_HANDLERS.iter().find(|x| x.ctype == ctype);
1865 let read_size;
1866 if let Some(handler) = handler {
1867 read_size = (handler.parse)(self, strmgr, size)?;
1868 } else {
1869 println!("skipping unknown chunk {:08X} size {}", ctype, size);
1870 read_size = 0;
1871 }
1872 validate!(read_size <= size);
1873 self.src.skip64(size - read_size)?;
1874 }
1875 //todo check if all needed chunks are found
1876 Ok(())
1877 }
1878 read_chunk_list!(root; "moov", read_moov, MOOV_CHUNK_HANDLERS);
1879 read_chunk_list!(root; "moof", read_moof, MOOF_CHUNK_HANDLERS);
1880 }
1881
1882 pub struct MOVDemuxerCreator { }
1883
1884 impl DemuxerCreator for MOVDemuxerCreator {
1885 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
1886 Box::new(MOVDemuxer::new(br))
1887 }
1888 fn get_name(&self) -> &'static str { "mov" }
1889 }
1890
1891 pub struct MacBinaryMOVDemuxerCreator { }
1892
1893 impl DemuxerCreator for MacBinaryMOVDemuxerCreator {
1894 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
1895 Box::new(MOVDemuxer::new_macbinary(br))
1896 }
1897 fn get_name(&self) -> &'static str { "mov-macbin" }
1898 }
1899
1900 const MOV_DEFAULT_PAL_2BIT: [u8; 4 * 4] = [
1901 0x93, 0x65, 0x5E, 0x00,
1902 0xFF, 0xFF, 0xFF, 0x00,
1903 0xDF, 0xD0, 0xAB, 0x00,
1904 0x00, 0x00, 0x00, 0x00
1905 ];
1906 const MOV_DEFAULT_PAL_4BIT: [u8; 16 * 4] = [
1907 0xFF, 0xFB, 0xFF, 0x00,
1908 0xEF, 0xD9, 0xBB, 0x00,
1909 0xE8, 0xC9, 0xB1, 0x00,
1910 0x93, 0x65, 0x5E, 0x00,
1911 0xFC, 0xDE, 0xE8, 0x00,
1912 0x9D, 0x88, 0x91, 0x00,
1913 0xFF, 0xFF, 0xFF, 0x00,
1914 0xFF, 0xFF, 0xFF, 0x00,
1915 0xFF, 0xFF, 0xFF, 0x00,
1916 0x47, 0x48, 0x37, 0x00,
1917 0x7A, 0x5E, 0x55, 0x00,
1918 0xDF, 0xD0, 0xAB, 0x00,
1919 0xFF, 0xFB, 0xF9, 0x00,
1920 0xE8, 0xCA, 0xC5, 0x00,
1921 0x8A, 0x7C, 0x77, 0x00,
1922 0x00, 0x00, 0x00, 0x00
1923 ];
1924 const MOV_DEFAULT_PAL_8BIT: [u8; 256 * 4] = [
1925 0xFF, 0xFF, 0xFF, 0x00,
1926 0xFF, 0xFF, 0xCC, 0x00,
1927 0xFF, 0xFF, 0x99, 0x00,
1928 0xFF, 0xFF, 0x66, 0x00,
1929 0xFF, 0xFF, 0x33, 0x00,
1930 0xFF, 0xFF, 0x00, 0x00,
1931 0xFF, 0xCC, 0xFF, 0x00,
1932 0xFF, 0xCC, 0xCC, 0x00,
1933 0xFF, 0xCC, 0x99, 0x00,
1934 0xFF, 0xCC, 0x66, 0x00,
1935 0xFF, 0xCC, 0x33, 0x00,
1936 0xFF, 0xCC, 0x00, 0x00,
1937 0xFF, 0x99, 0xFF, 0x00,
1938 0xFF, 0x99, 0xCC, 0x00,
1939 0xFF, 0x99, 0x99, 0x00,
1940 0xFF, 0x99, 0x66, 0x00,
1941 0xFF, 0x99, 0x33, 0x00,
1942 0xFF, 0x99, 0x00, 0x00,
1943 0xFF, 0x66, 0xFF, 0x00,
1944 0xFF, 0x66, 0xCC, 0x00,
1945 0xFF, 0x66, 0x99, 0x00,
1946 0xFF, 0x66, 0x66, 0x00,
1947 0xFF, 0x66, 0x33, 0x00,
1948 0xFF, 0x66, 0x00, 0x00,
1949 0xFF, 0x33, 0xFF, 0x00,
1950 0xFF, 0x33, 0xCC, 0x00,
1951 0xFF, 0x33, 0x99, 0x00,
1952 0xFF, 0x33, 0x66, 0x00,
1953 0xFF, 0x33, 0x33, 0x00,
1954 0xFF, 0x33, 0x00, 0x00,
1955 0xFF, 0x00, 0xFF, 0x00,
1956 0xFF, 0x00, 0xCC, 0x00,
1957 0xFF, 0x00, 0x99, 0x00,
1958 0xFF, 0x00, 0x66, 0x00,
1959 0xFF, 0x00, 0x33, 0x00,
1960 0xFF, 0x00, 0x00, 0x00,
1961 0xCC, 0xFF, 0xFF, 0x00,
1962 0xCC, 0xFF, 0xCC, 0x00,
1963 0xCC, 0xFF, 0x99, 0x00,
1964 0xCC, 0xFF, 0x66, 0x00,
1965 0xCC, 0xFF, 0x33, 0x00,
1966 0xCC, 0xFF, 0x00, 0x00,
1967 0xCC, 0xCC, 0xFF, 0x00,
1968 0xCC, 0xCC, 0xCC, 0x00,
1969 0xCC, 0xCC, 0x99, 0x00,
1970 0xCC, 0xCC, 0x66, 0x00,
1971 0xCC, 0xCC, 0x33, 0x00,
1972 0xCC, 0xCC, 0x00, 0x00,
1973 0xCC, 0x99, 0xFF, 0x00,
1974 0xCC, 0x99, 0xCC, 0x00,
1975 0xCC, 0x99, 0x99, 0x00,
1976 0xCC, 0x99, 0x66, 0x00,
1977 0xCC, 0x99, 0x33, 0x00,
1978 0xCC, 0x99, 0x00, 0x00,
1979 0xCC, 0x66, 0xFF, 0x00,
1980 0xCC, 0x66, 0xCC, 0x00,
1981 0xCC, 0x66, 0x99, 0x00,
1982 0xCC, 0x66, 0x66, 0x00,
1983 0xCC, 0x66, 0x33, 0x00,
1984 0xCC, 0x66, 0x00, 0x00,
1985 0xCC, 0x33, 0xFF, 0x00,
1986 0xCC, 0x33, 0xCC, 0x00,
1987 0xCC, 0x33, 0x99, 0x00,
1988 0xCC, 0x33, 0x66, 0x00,
1989 0xCC, 0x33, 0x33, 0x00,
1990 0xCC, 0x33, 0x00, 0x00,
1991 0xCC, 0x00, 0xFF, 0x00,
1992 0xCC, 0x00, 0xCC, 0x00,
1993 0xCC, 0x00, 0x99, 0x00,
1994 0xCC, 0x00, 0x66, 0x00,
1995 0xCC, 0x00, 0x33, 0x00,
1996 0xCC, 0x00, 0x00, 0x00,
1997 0x99, 0xFF, 0xFF, 0x00,
1998 0x99, 0xFF, 0xCC, 0x00,
1999 0x99, 0xFF, 0x99, 0x00,
2000 0x99, 0xFF, 0x66, 0x00,
2001 0x99, 0xFF, 0x33, 0x00,
2002 0x99, 0xFF, 0x00, 0x00,
2003 0x99, 0xCC, 0xFF, 0x00,
2004 0x99, 0xCC, 0xCC, 0x00,
2005 0x99, 0xCC, 0x99, 0x00,
2006 0x99, 0xCC, 0x66, 0x00,
2007 0x99, 0xCC, 0x33, 0x00,
2008 0x99, 0xCC, 0x00, 0x00,
2009 0x99, 0x99, 0xFF, 0x00,
2010 0x99, 0x99, 0xCC, 0x00,
2011 0x99, 0x99, 0x99, 0x00,
2012 0x99, 0x99, 0x66, 0x00,
2013 0x99, 0x99, 0x33, 0x00,
2014 0x99, 0x99, 0x00, 0x00,
2015 0x99, 0x66, 0xFF, 0x00,
2016 0x99, 0x66, 0xCC, 0x00,
2017 0x99, 0x66, 0x99, 0x00,
2018 0x99, 0x66, 0x66, 0x00,
2019 0x99, 0x66, 0x33, 0x00,
2020 0x99, 0x66, 0x00, 0x00,
2021 0x99, 0x33, 0xFF, 0x00,
2022 0x99, 0x33, 0xCC, 0x00,
2023 0x99, 0x33, 0x99, 0x00,
2024 0x99, 0x33, 0x66, 0x00,
2025 0x99, 0x33, 0x33, 0x00,
2026 0x99, 0x33, 0x00, 0x00,
2027 0x99, 0x00, 0xFF, 0x00,
2028 0x99, 0x00, 0xCC, 0x00,
2029 0x99, 0x00, 0x99, 0x00,
2030 0x99, 0x00, 0x66, 0x00,
2031 0x99, 0x00, 0x33, 0x00,
2032 0x99, 0x00, 0x00, 0x00,
2033 0x66, 0xFF, 0xFF, 0x00,
2034 0x66, 0xFF, 0xCC, 0x00,
2035 0x66, 0xFF, 0x99, 0x00,
2036 0x66, 0xFF, 0x66, 0x00,
2037 0x66, 0xFF, 0x33, 0x00,
2038 0x66, 0xFF, 0x00, 0x00,
2039 0x66, 0xCC, 0xFF, 0x00,
2040 0x66, 0xCC, 0xCC, 0x00,
2041 0x66, 0xCC, 0x99, 0x00,
2042 0x66, 0xCC, 0x66, 0x00,
2043 0x66, 0xCC, 0x33, 0x00,
2044 0x66, 0xCC, 0x00, 0x00,
2045 0x66, 0x99, 0xFF, 0x00,
2046 0x66, 0x99, 0xCC, 0x00,
2047 0x66, 0x99, 0x99, 0x00,
2048 0x66, 0x99, 0x66, 0x00,
2049 0x66, 0x99, 0x33, 0x00,
2050 0x66, 0x99, 0x00, 0x00,
2051 0x66, 0x66, 0xFF, 0x00,
2052 0x66, 0x66, 0xCC, 0x00,
2053 0x66, 0x66, 0x99, 0x00,
2054 0x66, 0x66, 0x66, 0x00,
2055 0x66, 0x66, 0x33, 0x00,
2056 0x66, 0x66, 0x00, 0x00,
2057 0x66, 0x33, 0xFF, 0x00,
2058 0x66, 0x33, 0xCC, 0x00,
2059 0x66, 0x33, 0x99, 0x00,
2060 0x66, 0x33, 0x66, 0x00,
2061 0x66, 0x33, 0x33, 0x00,
2062 0x66, 0x33, 0x00, 0x00,
2063 0x66, 0x00, 0xFF, 0x00,
2064 0x66, 0x00, 0xCC, 0x00,
2065 0x66, 0x00, 0x99, 0x00,
2066 0x66, 0x00, 0x66, 0x00,
2067 0x66, 0x00, 0x33, 0x00,
2068 0x66, 0x00, 0x00, 0x00,
2069 0x33, 0xFF, 0xFF, 0x00,
2070 0x33, 0xFF, 0xCC, 0x00,
2071 0x33, 0xFF, 0x99, 0x00,
2072 0x33, 0xFF, 0x66, 0x00,
2073 0x33, 0xFF, 0x33, 0x00,
2074 0x33, 0xFF, 0x00, 0x00,
2075 0x33, 0xCC, 0xFF, 0x00,
2076 0x33, 0xCC, 0xCC, 0x00,
2077 0x33, 0xCC, 0x99, 0x00,
2078 0x33, 0xCC, 0x66, 0x00,
2079 0x33, 0xCC, 0x33, 0x00,
2080 0x33, 0xCC, 0x00, 0x00,
2081 0x33, 0x99, 0xFF, 0x00,
2082 0x33, 0x99, 0xCC, 0x00,
2083 0x33, 0x99, 0x99, 0x00,
2084 0x33, 0x99, 0x66, 0x00,
2085 0x33, 0x99, 0x33, 0x00,
2086 0x33, 0x99, 0x00, 0x00,
2087 0x33, 0x66, 0xFF, 0x00,
2088 0x33, 0x66, 0xCC, 0x00,
2089 0x33, 0x66, 0x99, 0x00,
2090 0x33, 0x66, 0x66, 0x00,
2091 0x33, 0x66, 0x33, 0x00,
2092 0x33, 0x66, 0x00, 0x00,
2093 0x33, 0x33, 0xFF, 0x00,
2094 0x33, 0x33, 0xCC, 0x00,
2095 0x33, 0x33, 0x99, 0x00,
2096 0x33, 0x33, 0x66, 0x00,
2097 0x33, 0x33, 0x33, 0x00,
2098 0x33, 0x33, 0x00, 0x00,
2099 0x33, 0x00, 0xFF, 0x00,
2100 0x33, 0x00, 0xCC, 0x00,
2101 0x33, 0x00, 0x99, 0x00,
2102 0x33, 0x00, 0x66, 0x00,
2103 0x33, 0x00, 0x33, 0x00,
2104 0x33, 0x00, 0x00, 0x00,
2105 0x00, 0xFF, 0xFF, 0x00,
2106 0x00, 0xFF, 0xCC, 0x00,
2107 0x00, 0xFF, 0x99, 0x00,
2108 0x00, 0xFF, 0x66, 0x00,
2109 0x00, 0xFF, 0x33, 0x00,
2110 0x00, 0xFF, 0x00, 0x00,
2111 0x00, 0xCC, 0xFF, 0x00,
2112 0x00, 0xCC, 0xCC, 0x00,
2113 0x00, 0xCC, 0x99, 0x00,
2114 0x00, 0xCC, 0x66, 0x00,
2115 0x00, 0xCC, 0x33, 0x00,
2116 0x00, 0xCC, 0x00, 0x00,
2117 0x00, 0x99, 0xFF, 0x00,
2118 0x00, 0x99, 0xCC, 0x00,
2119 0x00, 0x99, 0x99, 0x00,
2120 0x00, 0x99, 0x66, 0x00,
2121 0x00, 0x99, 0x33, 0x00,
2122 0x00, 0x99, 0x00, 0x00,
2123 0x00, 0x66, 0xFF, 0x00,
2124 0x00, 0x66, 0xCC, 0x00,
2125 0x00, 0x66, 0x99, 0x00,
2126 0x00, 0x66, 0x66, 0x00,
2127 0x00, 0x66, 0x33, 0x00,
2128 0x00, 0x66, 0x00, 0x00,
2129 0x00, 0x33, 0xFF, 0x00,
2130 0x00, 0x33, 0xCC, 0x00,
2131 0x00, 0x33, 0x99, 0x00,
2132 0x00, 0x33, 0x66, 0x00,
2133 0x00, 0x33, 0x33, 0x00,
2134 0x00, 0x33, 0x00, 0x00,
2135 0x00, 0x00, 0xFF, 0x00,
2136 0x00, 0x00, 0xCC, 0x00,
2137 0x00, 0x00, 0x99, 0x00,
2138 0x00, 0x00, 0x66, 0x00,
2139 0x00, 0x00, 0x33, 0x00,
2140 0xEE, 0x00, 0x00, 0x00,
2141 0xDD, 0x00, 0x00, 0x00,
2142 0xBB, 0x00, 0x00, 0x00,
2143 0xAA, 0x00, 0x00, 0x00,
2144 0x88, 0x00, 0x00, 0x00,
2145 0x77, 0x00, 0x00, 0x00,
2146 0x55, 0x00, 0x00, 0x00,
2147 0x44, 0x00, 0x00, 0x00,
2148 0x22, 0x00, 0x00, 0x00,
2149 0x11, 0x00, 0x00, 0x00,
2150 0x00, 0xEE, 0x00, 0x00,
2151 0x00, 0xDD, 0x00, 0x00,
2152 0x00, 0xBB, 0x00, 0x00,
2153 0x00, 0xAA, 0x00, 0x00,
2154 0x00, 0x88, 0x00, 0x00,
2155 0x00, 0x77, 0x00, 0x00,
2156 0x00, 0x55, 0x00, 0x00,
2157 0x00, 0x44, 0x00, 0x00,
2158 0x00, 0x22, 0x00, 0x00,
2159 0x00, 0x11, 0x00, 0x00,
2160 0x00, 0x00, 0xEE, 0x00,
2161 0x00, 0x00, 0xDD, 0x00,
2162 0x00, 0x00, 0xBB, 0x00,
2163 0x00, 0x00, 0xAA, 0x00,
2164 0x00, 0x00, 0x88, 0x00,
2165 0x00, 0x00, 0x77, 0x00,
2166 0x00, 0x00, 0x55, 0x00,
2167 0x00, 0x00, 0x44, 0x00,
2168 0x00, 0x00, 0x22, 0x00,
2169 0x00, 0x00, 0x11, 0x00,
2170 0xEE, 0xEE, 0xEE, 0x00,
2171 0xDD, 0xDD, 0xDD, 0x00,
2172 0xBB, 0xBB, 0xBB, 0x00,
2173 0xAA, 0xAA, 0xAA, 0x00,
2174 0x88, 0x88, 0x88, 0x00,
2175 0x77, 0x77, 0x77, 0x00,
2176 0x55, 0x55, 0x55, 0x00,
2177 0x44, 0x44, 0x44, 0x00,
2178 0x22, 0x22, 0x22, 0x00,
2179 0x11, 0x11, 0x11, 0x00,
2180 0x00, 0x00, 0x00, 0x00
2181 ];
2182
2183 #[cfg(test)]
2184 mod test {
2185 use super::*;
2186 use std::fs::File;
2187
2188 #[test]
2189 fn test_mov_demux() {
2190 // sample: https://samples.mplayerhq.hu/V-codecs/IV32/cubes.mov
2191 let mut file = File::open("assets/Indeo/cubes.mov").unwrap();
2192 let mut fr = FileReader::new_read(&mut file);
2193 let mut br = ByteReader::new(&mut fr);
2194 let mut dmx = MOVDemuxer::new(&mut br);
2195 let mut sm = StreamManager::new();
2196 let mut si = SeekIndex::new();
2197 dmx.open(&mut sm, &mut si).unwrap();
2198
2199 loop {
2200 let pktres = dmx.get_frame(&mut sm);
2201 if let Err(e) = pktres {
2202 if e == DemuxerError::EOF { break; }
2203 panic!("error");
2204 }
2205 let pkt = pktres.unwrap();
2206 println!("Got {}", pkt);
2207 }
2208 }
2209
2210 #[test]
2211 fn test_dash_demux() {
2212 // sample: a stream downloaded with youtube-dl
2213 let mut file = File::open("assets/ITU/dash.m4a").unwrap();
2214 let mut fr = FileReader::new_read(&mut file);
2215 let mut br = ByteReader::new(&mut fr);
2216 let mut dmx = MOVDemuxer::new(&mut br);
2217 let mut sm = StreamManager::new();
2218 let mut si = SeekIndex::new();
2219 dmx.open(&mut sm, &mut si).unwrap();
2220
2221 loop {
2222 let pktres = dmx.get_frame(&mut sm);
2223 if let Err(e) = pktres {
2224 if e == DemuxerError::EOF { break; }
2225 panic!("error");
2226 }
2227 let pkt = pktres.unwrap();
2228 println!("Got {}", pkt);
2229 }
2230 }
2231
2232 #[test]
2233 fn test_macbinary_demux() {
2234 // sample from King's Quest VI Macintosh edition
2235 let mut file = File::open("assets/QT/Halfdome.bin").unwrap();
2236 let mut fr = FileReader::new_read(&mut file);
2237 let mut br = ByteReader::new(&mut fr);
2238 let mut dmx = MOVDemuxer::new_macbinary(&mut br);
2239 let mut sm = StreamManager::new();
2240 let mut si = SeekIndex::new();
2241 dmx.open(&mut sm, &mut si).unwrap();
2242
2243 loop {
2244 let pktres = dmx.get_frame(&mut sm);
2245 if let Err(e) = pktres {
2246 if e == DemuxerError::EOF { break; }
2247 panic!("error");
2248 }
2249 let pkt = pktres.unwrap();
2250 println!("Got {}", pkt);
2251 }
2252 }
2253 }