add MCMP demuxer
[nihav.git] / nihav-game / src / demuxers / smush.rs
1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
3
4 struct SmushDemuxer<'a> {
5 src: &'a mut ByteReader<'a>,
6 old: bool,
7 size: u64,
8
9 nframes: usize,
10 chunks: Vec<u8>,
11
12 keyframe: bool,
13 cur_frame: usize,
14 frme_end: u64,
15 asize: u64,
16 }
17
18 fn parse_iact(br: &mut ByteReader, end: u64, arate: &mut u32, abits: &mut u8, chans: &mut u8, mcmp: bool) -> DemuxerResult<()> {
19 if !mcmp {
20 br.read_skip(14)?;
21 }
22 let tag = br.read_tag()?;
23 if &tag != b"iMUS" {
24 if mcmp {
25 return Err(DemuxerError::InvalidData);
26 }
27 *arate = 22050;
28 *abits = 16;
29 *chans = 2;
30 return Ok(());
31 }
32 br.read_skip(4)?;
33 while br.tell() < end {
34 let tag = br.read_tag()?;
35 let size = u64::from(br.read_u32be()?);
36 match &tag {
37 b"MAP " => {
38 let cend = br.tell() + size;
39 while br.tell() < cend {
40 let tag = br.read_tag()?;
41 let size = u64::from(br.read_u32be()?);
42 match &tag {
43 b"FRMT" => {
44 validate!(size == 20);
45 br.read_u32be()?;
46 br.read_u32be()?;
47 let bits = br.read_u32be()?;
48 validate!(bits > 0 && bits <= 16);
49 *abits = bits as u8;
50 *arate = br.read_u32be()?;
51 let c = br.read_u32be()?;
52 validate!(c == 1 || c == 2);
53 *chans = c as u8;
54 return Ok(());
55 },
56 _ => br.read_skip(size as usize)?,
57 };
58 }
59 },
60 b"DATA" => return Err(DemuxerError::InvalidData),
61 _ => br.read_skip(size as usize)?,
62 };
63 }
64 Err(DemuxerError::InvalidData)
65 }
66
67 impl<'a> SmushDemuxer<'a> {
68 fn new(io: &'a mut ByteReader<'a>) -> Self {
69 SmushDemuxer {
70 src: io,
71
72 old: false,
73 size: 0,
74
75 nframes: 0,
76 chunks: Vec::new(),
77
78 keyframe: false,
79 cur_frame: 0,
80 frme_end: 0,
81 asize: 0,
82 }
83 }
84 fn parse_anim_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
85 let src = &mut self.src;
86
87 let tag = src.read_tag()?;
88 validate!(&tag == b"AHDR");
89 let size = u64::from(src.read_u32be()?);
90 validate!(size >= 768 + 6);
91 let end = src.tell() + size;
92 validate!(end < self.size);
93 let version = src.read_u16le()?;
94 validate!(version < 3);
95 self.nframes = src.read_u16le()? as usize;
96 validate!(self.nframes != 0);
97 src.read_skip(2)?; //max FRME size
98 let mut edata = vec![0; 768 + 1];
99 edata[0] = version as u8;
100 src.read_buf(&mut edata[1..][..768])?;
101 src.read_skip(size as usize - 768 - 6)?;
102
103 let start = src.tell();
104 let mut size = 0;
105 while size == 0 {
106 let tag = src.read_tag()?;
107 validate!(&tag == b"FRME");
108 size = u64::from(src.read_u32be()?);
109 }
110
111 let end = src.tell() + size;
112 validate!(end <= self.size + 8); // some NUTs feature slightly incorrect total size
113
114 let mut width = 0;
115 let mut height = 0;
116 let mut aname = "";
117 let mut arate = 0;
118 let mut abits = 0;
119 let mut chans = 0;
120
121 while src.tell() < end {
122 let tag = src.read_tag()?;
123 let size = u64::from(src.read_u32be()?);
124
125 let tend = src.tell() + size;
126 validate!(tend <= end);
127 match &tag {
128 b"FOBJ" => {
129 validate!(size >= 10);
130 let _codec = src.read_u16le()?;
131 let x = src.read_u16le()? as i16;
132 let y = src.read_u16le()? as i16;
133 if x == 0 && y == 0 && width == 0 && height == 0 {
134 width = src.read_u16le()? as usize;
135 height = src.read_u16le()? as usize;
136 } else {
137 let w = src.read_u16le()? as usize;
138 let h = src.read_u16le()? as usize;
139 if x == 0 && y == 0 && w >= width && h >= height {
140 width = w;
141 height = h;
142 }
143 }
144 src.read_skip((size - 10) as usize)?;
145 },
146 b"IACT" => {
147 validate!(size > 8);
148 let end = src.tell() + size;
149 let opcode = src.read_u16le()?;
150 let flags = src.read_u16le()?;
151 if (opcode == 8) && (flags == 0x2E) {
152 if parse_iact(src, end, &mut arate, &mut abits, &mut chans, false).is_ok() {
153 aname = "smush-iact";
154 }
155 validate!(src.tell() <= end);
156 }
157 src.seek(SeekFrom::Start(end))?;
158 },
159 b"PSAD" => {
160 aname = "pcm";
161 arate = 11025;
162 abits = 8;
163 chans = 2;
164 src.read_skip(size as usize)?;
165 },
166 _ => { src.read_skip(size as usize)?; },
167 };
168 if (src.tell() & 1) != 0 {
169 if let Ok(0) = src.peek_byte() {
170 src.read_skip(1)?;
171 }
172 }
173 }
174 // hack
175 width = width.max(320);
176 height = height.max(200);
177 src.seek(SeekFrom::Start(start))?;
178 self.frme_end = start;
179
180 let vhdr = NAVideoInfo::new(width, height, false, PAL8_FORMAT);
181 let vci = NACodecTypeInfo::Video(vhdr);
182 let vinfo = NACodecInfo::new("smushv1", vci, Some(edata));
183 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 15, self.nframes as u64)).is_none() {
184 return Err(DemuxerError::MemoryError);
185 }
186
187 if !aname.is_empty() {
188 validate!(arate > 0);
189 let mut fmt = SND_S16_FORMAT;
190 match aname {
191 "pcm" => { fmt = SND_U8_FORMAT; },
192 "smush-iact" => { fmt.bits = abits; fmt.packed = true; },
193 _ => {},
194 };
195 let ahdr = NAAudioInfo::new(arate, chans, fmt, 0);
196 let ainfo = NACodecInfo::new(aname, NACodecTypeInfo::Audio(ahdr), None);
197 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, arate, 0)).is_none() {
198 return Err(DemuxerError::MemoryError);
199 }
200 }
201
202 Ok(())
203 }
204 fn parse_sanm_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
205 let src = &mut self.src;
206
207 let tag = src.read_tag()?;
208 validate!(&tag == b"SHDR");
209 let size = u64::from(src.read_u32be()?);
210 validate!(src.tell() + size <= self.size);
211 validate!(size >= 0x426);
212
213 let maj_ver = src.read_byte()?;
214 let min_ver = src.read_byte()?;
215 if maj_ver != 1 || min_ver != 0 {
216 return Err(DemuxerError::NotImplemented);
217 }
218 self.nframes = src.read_u16le()? as usize;
219 let _xoff = src.read_u16le()? as usize;
220 let _yoff = src.read_u16le()? as usize;
221 let width = src.read_u16le()? as usize;
222 let height = src.read_u16le()? as usize;
223 let _imgtype = src.read_u16le()?;
224 let frame_delay = src.read_u32le()?;
225 let _max_frame_size = src.read_u32le()?;
226 src.read_skip(1024)?; // palette
227 src.read_skip((size as usize) - 0x416)?;
228
229 let tag = src.read_tag()?;
230 validate!(&tag == b"FLHD");
231 let size = u64::from(src.read_u32be()?);
232 let end = src.tell() + size;
233
234 let mut arate = 0;
235 let mut chans = 0;
236 let mut alen = 0;
237 while src.tell() < end {
238 let tag = src.read_tag()?;
239 if src.tell() == end { break; }
240 let size = src.read_u32be()?;
241 match &tag {
242 b"Wave" => {
243 validate!(size >= 8);
244 arate = src.read_u32le()?;
245 let cc = src.read_u32le()?;
246 validate!(cc == 1 || cc == 2);
247 chans = cc as u8;
248 if size >= 12 {
249 alen = u64::from(src.read_u32le()? / cc / 2);
250 src.read_skip((size as usize) - 12)?;
251 }
252 },
253 _ => src.read_skip(size as usize)?,
254 };
255 }
256 validate!(src.tell() == end);
257
258 let vhdr = NAVideoInfo::new(width, height, false, RGB565_FORMAT);
259 let vci = NACodecTypeInfo::Video(vhdr);
260 let vinfo = NACodecInfo::new("smushv2", vci, None);
261 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, frame_delay, 1000000, self.nframes as u64)).is_none() {
262 return Err(DemuxerError::MemoryError);
263 }
264 if arate != 0 {
265 let ahdr = NAAudioInfo::new(arate, chans, SND_S16P_FORMAT, 0);
266 let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None);
267 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, arate, alen)).is_none() {
268 return Err(DemuxerError::MemoryError);
269 }
270 }
271
272 Ok(())
273 }
274
275 fn queue_chunk(&mut self, tag: [u8; 4], size: usize) -> DemuxerResult<()> {
276 self.chunks.extend_from_slice(&tag);
277 let start = self.chunks.len();
278 let nlen = start + size + 4;
279 self.chunks.resize(nlen, 0);
280 write_u32be(&mut self.chunks[start..], size as u32).unwrap();
281 self.src.read_buf(&mut self.chunks[start + 4..])?;
282 Ok(())
283 }
284 fn get_frame_anim(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
285 loop {
286 if self.src.tell() >= self.frme_end {
287 if !self.chunks.is_empty() {
288 let mut buf = Vec::new();
289 std::mem::swap(&mut self.chunks, &mut buf);
290 let stream = strmgr.get_stream(0).unwrap();
291 let (tb_num, tb_den) = stream.get_timebase();
292 let ts = NATimeInfo::new(Some(self.cur_frame as u64 - 1), None, None, tb_num, tb_den);
293 return Ok(NAPacket::new(stream, ts, false, buf));
294 }
295 if self.cur_frame == self.nframes {
296 return Err(DemuxerError::EOF);
297 }
298 let tag = self.src.read_tag()?;
299 validate!(&tag == b"FRME");
300 let size = u64::from(self.src.read_u32be()?);
301 self.frme_end = self.src.tell() + size;
302
303 self.chunks.clear();
304 self.cur_frame += 1;
305 if size == 0 {
306 continue;
307 }
308 }
309 let tag = self.src.read_tag()?;
310 let size = u64::from(self.src.read_u32be()?);
311 let tend = self.src.tell() + size;
312 validate!(tend <= self.frme_end);
313 match &tag {
314 b"STOR" | b"FTCH" | b"NPAL" | b"XPAL" | b"FOBJ" => {
315 self.queue_chunk(tag, size as usize)?;
316 },
317 b"IACT" => {
318 validate!(size >= 4);
319 let opcode = self.src.read_u16le()?;
320 let flags = self.src.read_u16le()?;
321 if (opcode == 8) && (flags == 0x2E) {
322 if let Some(stream) = strmgr.get_stream(1) {
323 let (tb_num, tb_den) = stream.get_timebase();
324 let ts = NATimeInfo::new(None, None, None, tb_num, tb_den);
325
326 let mut buf = vec![0; size as usize];
327 write_u16le(&mut buf[0..2], opcode).unwrap();
328 write_u16le(&mut buf[2..4], flags).unwrap();
329 self.src.read_buf(&mut buf[4..])?;
330
331 if (self.src.tell() & 1) == 1 {
332 if let Ok(0) = self.src.peek_byte() {
333 self.src.read_skip(1)?;
334 }
335 }
336 return Ok(NAPacket::new(stream, ts, true, buf));
337 }
338 }
339 self.src.read_skip((size as usize) - 4)?;
340 },
341 b"PSAD" => {
342 if size > 0x30 {
343 self.src.read_skip(0x30)?;
344 if let Some(stream) = strmgr.get_stream(1) {
345 let (tb_num, tb_den) = stream.get_timebase();
346
347 let audio_size = size - 0x30;
348 let ts = NATimeInfo::new(Some(self.asize), None, None, tb_num, tb_den);
349 let pkt = self.src.read_packet(stream, ts, true, audio_size as usize)?;
350 self.asize += audio_size;
351 if (self.src.tell() & 1) == 1 {
352 if let Ok(0) = self.src.peek_byte() {
353 self.src.read_skip(1)?;
354 }
355 }
356 return Ok(pkt);
357 } else {
358 self.src.read_skip((size - 0x30) as usize)?;
359 }
360 } else {
361 self.src.read_skip(size as usize)?;
362 }
363 },
364 _ => {
365 self.src.read_skip(size as usize)?;
366 },
367 };
368 if (self.src.tell() & 1) == 1 {
369 if let Ok(0) = self.src.peek_byte() {
370 self.src.read_skip(1)?;
371 }
372 }
373 }
374 }
375 fn get_frame_sanm(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
376 loop {
377 if self.src.tell() >= self.frme_end {
378 if !self.chunks.is_empty() {
379 let mut buf = Vec::new();
380 std::mem::swap(&mut self.chunks, &mut buf);
381 let stream = strmgr.get_stream(0).unwrap();
382 let (tb_num, tb_den) = stream.get_timebase();
383 let ts = NATimeInfo::new(Some(self.cur_frame as u64 - 1), None, None, tb_num, tb_den);
384 return Ok(NAPacket::new(stream, ts, self.keyframe, buf));
385 }
386 if self.cur_frame == self.nframes {
387 return Err(DemuxerError::EOF);
388 }
389 let tag = self.src.read_tag()?;
390 let size = u64::from(self.src.read_u32be()?);
391 self.frme_end = self.src.tell() + size;
392 match &tag {
393 b"FLHD" => { self.keyframe = true; },
394 b"FRME" => { self.keyframe = false; },
395 _ => {
396 self.src.read_skip(size as usize)?;
397 continue;
398 },
399 };
400
401 self.chunks.clear();
402 self.cur_frame += 1;
403 if size == 0 {
404 continue;
405 }
406 }
407 let tag = self.src.read_tag()?;
408 if self.src.tell() >= self.frme_end { // happens after some Wave tags
409 continue;
410 }
411 let size = u64::from(self.src.read_u32be()?);
412 let tend = self.src.tell() + size;
413 validate!(tend <= self.frme_end);
414 match &tag {
415 b"Bl16" => {
416 self.queue_chunk(tag, size as usize)?;
417 },
418 b"Wave" => {
419 if let Some(stream) = strmgr.get_stream(1) {
420 let mut buf = [0; 12];
421 let mut nsamples = 0;
422 if size >= 12 {
423 self.src.peek_buf(&mut buf)?;
424 nsamples = read_u32be(&buf[0..])?;
425 if nsamples == 0xFFFFFFFF {
426 nsamples = read_u32be(&buf[8..])?;
427 }
428 }
429
430 let (tb_num, tb_den) = stream.get_timebase();
431 let mut ts = NATimeInfo::new(None, None, None, tb_num, tb_den);
432 if nsamples != 0 {
433 ts.pts = Some(self.asize);
434 self.asize += u64::from(nsamples);
435 }
436 let pkt = self.src.read_packet(stream, ts, true, size as usize)?;
437 return Ok(pkt);
438 } else {
439 self.src.read_skip(size as usize)?;
440 }
441 },
442 _ => {
443 //println!("unknown tag {}{}{}{} size {:X} @ {:X}", tag[0] as char, tag[1] as char, tag[2] as char, tag[3] as char, size, self.src.tell() - 8);
444 self.src.read_skip(size as usize)?;
445 },
446 };
447 }
448 }
449 }
450
451 impl<'a> DemuxCore<'a> for SmushDemuxer<'a> {
452 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
453 let magic = self.src.read_tag()?;
454 match &magic {
455 b"ANIM" => {
456 self.old = true;
457 },
458 b"SANM" => {
459 self.old = false;
460 },
461 _ => return Err(DemuxerError::InvalidData),
462 };
463 self.size = u64::from(self.src.read_u32be()?);
464 if self.old {
465 self.parse_anim_header(strmgr)?;
466 } else {
467 self.parse_sanm_header(strmgr)?;
468 }
469
470 self.cur_frame = 0;
471 Ok(())
472 }
473
474 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
475 if self.cur_frame > self.nframes { return Err(DemuxerError::EOF); }
476 if self.old {
477 self.get_frame_anim(strmgr)
478 } else {
479 self.get_frame_sanm(strmgr)
480 }
481 }
482
483 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
484 Err(DemuxerError::NotPossible)
485 }
486 fn get_duration(&self) -> u64 { 0 }
487 }
488
489 impl<'a> NAOptionHandler for SmushDemuxer<'a> {
490 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
491 fn set_options(&mut self, _options: &[NAOption]) { }
492 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
493 }
494
495 pub struct SmushDemuxerCreator { }
496
497 impl DemuxerCreator for SmushDemuxerCreator {
498 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
499 Box::new(SmushDemuxer::new(br))
500 }
501 fn get_name(&self) -> &'static str { "smush" }
502 }
503
504
505 struct MCMPDemuxer<'a> {
506 src: &'a mut ByteReader<'a>,
507 cur_frame: usize,
508
509 offsets: Vec<u64>,
510 sizes: Vec<u32>,
511 samples: Vec<u32>,
512 pts: Vec<u64>,
513 }
514
515 impl<'a> MCMPDemuxer<'a> {
516 fn new(io: &'a mut ByteReader<'a>) -> Self {
517 MCMPDemuxer {
518 src: io,
519 cur_frame: 0,
520
521 offsets: Vec::new(),
522 sizes: Vec::new(),
523 samples: Vec::new(),
524 pts: Vec::new(),
525 }
526 }
527 }
528
529 impl<'a> DemuxCore<'a> for MCMPDemuxer<'a> {
530 fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
531 let magic = self.src.read_tag()?;
532 validate!(&magic == b"MCMP");
533 let nframes = self.src.read_u16be()? as usize;
534 validate!(nframes > 1);
535 let cmp = self.src.read_byte()?;
536 let size1 = self.src.read_u32be()?;
537 let hdr_size = self.src.read_u32be()?;
538 validate!(cmp == 0 && size1 == hdr_size);
539
540 let size = (nframes - 1) as usize;
541 self.offsets = Vec::with_capacity(size);
542 self.sizes = Vec::with_capacity(size);
543 self.samples = Vec::with_capacity(size);
544 self.pts = Vec::with_capacity(size);
545
546 let mut start = 0;
547 let mut pts = 0;
548 for _ in 1..nframes {
549 let compr = self.src.read_byte()?;
550 if compr != 1 {
551 return Err(DemuxerError::NotImplemented);
552 }
553 let samples = self.src.read_u32be()? / 2;
554 let size = self.src.read_u32be()?;
555 self.offsets.push(start);
556 self.sizes.push(size);
557 self.samples.push(samples);
558 self.pts.push(pts);
559
560 start += u64::from(size);
561 pts += u64::from(samples);
562 }
563
564 let codecs_desc_size = self.src.read_u16be()? as usize;
565 // todo check it's NULL+VIMA
566 self.src.read_skip(codecs_desc_size)?;
567 let data_start = self.src.tell() + u64::from(hdr_size);
568 let mut arate = 0;
569 let mut abits = 0;
570 let mut chans = 0;
571 parse_iact(&mut self.src, data_start, &mut arate, &mut abits, &mut chans, true)?;
572 if chans == 2 {
573 for (samp, pts) in self.samples.iter_mut().zip(self.pts.iter_mut()) {
574 validate!((*samp & 1) == 0);
575 *samp >>= 1;
576 *pts >>= 1;
577 }
578 pts >>= 1;
579 }
580
581 let ahdr = NAAudioInfo::new(arate, chans, SND_S16_FORMAT, 0);
582 let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None);
583 if strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, arate, pts)).is_none() {
584 return Err(DemuxerError::MemoryError);
585 }
586
587 seek_index.mode = SeekIndexMode::Present;
588 seek_index.add_stream(0);
589 let index = seek_index.get_stream_index(0).unwrap();
590 for (i, (off, &pts)) in self.offsets.iter_mut().zip(self.pts.iter()).enumerate() {
591 *off += data_start;
592 index.add_entry(SeekEntry { time: pts * 1000 / u64::from(arate), pts, pos: i as u64 });
593 }
594 index.filled = true;
595
596 self.cur_frame = 0;
597 Ok(())
598 }
599
600 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
601 let idx = self.cur_frame;
602 if idx >= self.offsets.len() { return Err(DemuxerError::EOF); }
603 self.src.seek(SeekFrom::Start(self.offsets[idx]))?;
604 let mut buf = vec![0; self.sizes[idx] as usize + 4];
605 write_u32be(&mut buf, self.samples[idx])?;
606 self.src.read_buf(&mut buf[4..])?;
607
608 let stream = strmgr.get_stream(0).unwrap();
609 let (tb_num, tb_den) = stream.get_timebase();
610 let ts = NATimeInfo::new(Some(self.pts[idx]), None, None, tb_num, tb_den);
611
612 self.cur_frame += 1;
613
614 Ok(NAPacket::new(stream, ts, true, buf))
615 }
616
617 fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
618 if let Some(ret) = seek_index.find_pos(time) {
619 self.cur_frame = ret.pos as usize;
620 Ok(())
621 } else {
622 Err(DemuxerError::SeekError)
623 }
624 }
625 fn get_duration(&self) -> u64 { 0 }
626 }
627
628 impl<'a> NAOptionHandler for MCMPDemuxer<'a> {
629 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
630 fn set_options(&mut self, _options: &[NAOption]) { }
631 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
632 }
633
634 pub struct MCMPDemuxerCreator { }
635
636 impl DemuxerCreator for MCMPDemuxerCreator {
637 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
638 Box::new(MCMPDemuxer::new(br))
639 }
640 fn get_name(&self) -> &'static str { "smush-mcmp" }
641 }
642
643
644 #[cfg(test)]
645 mod test {
646 use super::*;
647 use std::fs::File;
648
649 #[test]
650 fn test_smush_demux_anim_v1() {
651 // sample from Rebel Assault game
652 let mut file = File::open("assets/Game/smush/c1block.anm").unwrap();
653 let mut fr = FileReader::new_read(&mut file);
654 let mut br = ByteReader::new(&mut fr);
655 let mut dmx = SmushDemuxer::new(&mut br);
656 let mut sm = StreamManager::new();
657 let mut si = SeekIndex::new();
658 dmx.open(&mut sm, &mut si).unwrap();
659 loop {
660 let pktres = dmx.get_frame(&mut sm);
661 if let Err(e) = pktres {
662 if (e as i32) == (DemuxerError::EOF as i32) { break; }
663 panic!("error");
664 }
665 let pkt = pktres.unwrap();
666 println!("Got {}", pkt);
667 }
668 }
669 #[test]
670 fn test_smush_demux_anim_v2() {
671 // sample from The Dig
672 let mut file = File::open("assets/Game/smush/PIGOUT.SAN").unwrap();
673 let mut fr = FileReader::new_read(&mut file);
674 let mut br = ByteReader::new(&mut fr);
675 let mut dmx = SmushDemuxer::new(&mut br);
676 let mut sm = StreamManager::new();
677 let mut si = SeekIndex::new();
678 dmx.open(&mut sm, &mut si).unwrap();
679 loop {
680 let pktres = dmx.get_frame(&mut sm);
681 if let Err(e) = pktres {
682 if (e as i32) == (DemuxerError::EOF as i32) { break; }
683 panic!("error");
684 }
685 let pkt = pktres.unwrap();
686 println!("Got {}", pkt);
687 }
688 }
689 #[test]
690 fn test_smush_demux_sanm() {
691 // sample from Grim Fandango
692 let mut file = File::open("assets/Game/smush/lol.snm").unwrap();
693 let mut fr = FileReader::new_read(&mut file);
694 let mut br = ByteReader::new(&mut fr);
695 let mut dmx = SmushDemuxer::new(&mut br);
696 let mut sm = StreamManager::new();
697 let mut si = SeekIndex::new();
698 dmx.open(&mut sm, &mut si).unwrap();
699 loop {
700 let pktres = dmx.get_frame(&mut sm);
701 if let Err(e) = pktres {
702 if (e as i32) == (DemuxerError::EOF as i32) { break; }
703 panic!("error");
704 }
705 let pkt = pktres.unwrap();
706 println!("Got {}", pkt);
707 }
708 }
709 #[test]
710 fn test_mcmp_demux() {
711 // sample from Grim Fandango
712 let mut file = File::open("assets/Game/smush/1104 - Lupe.IMC").unwrap();
713 let mut fr = FileReader::new_read(&mut file);
714 let mut br = ByteReader::new(&mut fr);
715 let mut dmx = MCMPDemuxer::new(&mut br);
716 let mut sm = StreamManager::new();
717 let mut si = SeekIndex::new();
718 dmx.open(&mut sm, &mut si).unwrap();
719 loop {
720 let pktres = dmx.get_frame(&mut sm);
721 if let Err(e) = pktres {
722 if (e as i32) == (DemuxerError::EOF as i32) { break; }
723 panic!("error");
724 }
725 let pkt = pktres.unwrap();
726 println!("Got {}", pkt);
727 }
728 }
729 }