1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
4 struct SmushDemuxer<'a> {
5 src: &'a mut ByteReader<'a>,
18 fn parse_iact(br: &mut ByteReader, end: u64, arate: &mut u32, abits: &mut u8, chans: &mut u8, mcmp: bool) -> DemuxerResult<()> {
22 let tag = br.read_tag()?;
25 return Err(DemuxerError::InvalidData);
33 while br.tell() < end {
34 let tag = br.read_tag()?;
35 let size = u64::from(br.read_u32be()?);
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()?);
44 validate!(size == 20);
47 let bits = br.read_u32be()?;
48 validate!(bits > 0 && bits <= 16);
50 *arate = br.read_u32be()?;
51 let c = br.read_u32be()?;
52 validate!(c == 1 || c == 2);
56 _ => br.read_skip(size as usize)?,
60 b"DATA" => return Err(DemuxerError::InvalidData),
61 _ => br.read_skip(size as usize)?,
64 Err(DemuxerError::InvalidData)
67 impl<'a> SmushDemuxer<'a> {
68 fn new(io: &'a mut ByteReader<'a>) -> Self {
84 fn parse_anim_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
85 let src = &mut self.src;
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)?;
103 let start = src.tell();
106 let tag = src.read_tag()?;
107 validate!(&tag == b"FRME");
108 size = u64::from(src.read_u32be()?);
111 let end = src.tell() + size;
112 validate!(end <= self.size + 8); // some NUTs feature slightly incorrect total size
121 while src.tell() < end {
122 let tag = src.read_tag()?;
123 let size = u64::from(src.read_u32be()?);
125 let tend = src.tell() + size;
126 validate!(tend <= end);
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;
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 {
144 src.read_skip((size - 10) as usize)?;
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";
155 validate!(src.tell() <= end);
157 src.seek(SeekFrom::Start(end))?;
164 src.read_skip(size as usize)?;
166 _ => { src.read_skip(size as usize)?; },
168 if (src.tell() & 1) != 0 {
169 if let Ok(0) = src.peek_byte() {
175 width = width.max(320);
176 height = height.max(200);
177 src.seek(SeekFrom::Start(start))?;
178 self.frme_end = start;
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);
187 if !aname.is_empty() {
188 validate!(arate > 0);
189 let mut fmt = SND_S16_FORMAT;
191 "pcm" => { fmt = SND_U8_FORMAT; },
192 "smush-iact" => { fmt.bits = abits; fmt.packed = true; },
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);
204 fn parse_sanm_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
205 let src = &mut self.src;
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);
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);
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)?;
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;
237 while src.tell() < end {
238 let tag = src.read_tag()?;
239 if src.tell() == end { break; }
240 let size = src.read_u32be()?;
243 validate!(size >= 8);
244 arate = src.read_u32le()?;
245 let cc = src.read_u32le()?;
246 validate!(cc == 1 || cc == 2);
249 alen = u64::from(src.read_u32le()? / cc / 2);
250 src.read_skip((size as usize) - 12)?;
253 _ => src.read_skip(size as usize)?,
256 validate!(src.tell() == end);
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);
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);
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..])?;
284 fn get_frame_anim(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
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 ts = stream.make_ts(Some(self.cur_frame as u64 - 1), None, None);
292 return Ok(NAPacket::new(stream, ts, false, buf));
294 if self.cur_frame == self.nframes {
295 return Err(DemuxerError::EOF);
297 let tag = self.src.read_tag()?;
298 validate!(&tag == b"FRME");
299 let size = u64::from(self.src.read_u32be()?);
300 self.frme_end = self.src.tell() + size;
308 let tag = self.src.read_tag()?;
309 let size = u64::from(self.src.read_u32be()?);
310 let tend = self.src.tell() + size;
311 validate!(tend <= self.frme_end);
313 b"STOR" | b"FTCH" | b"NPAL" | b"XPAL" | b"FOBJ" => {
314 self.queue_chunk(tag, size as usize)?;
317 validate!(size >= 4);
318 let opcode = self.src.read_u16le()?;
319 let flags = self.src.read_u16le()?;
320 if (opcode == 8) && (flags == 0x2E) {
321 if let Some(stream) = strmgr.get_stream(1) {
322 let ts = stream.make_ts(None, None, None);
324 let mut buf = vec![0; size as usize];
325 write_u16le(&mut buf[0..2], opcode).unwrap();
326 write_u16le(&mut buf[2..4], flags).unwrap();
327 self.src.read_buf(&mut buf[4..])?;
329 if (self.src.tell() & 1) == 1 {
330 if let Ok(0) = self.src.peek_byte() {
331 self.src.read_skip(1)?;
334 return Ok(NAPacket::new(stream, ts, true, buf));
337 self.src.read_skip((size as usize) - 4)?;
341 self.src.read_skip(0x30)?;
342 if let Some(stream) = strmgr.get_stream(1) {
343 let audio_size = size - 0x30;
344 let ts = stream.make_ts(Some(self.asize), None, None);
345 let pkt = self.src.read_packet(stream, ts, true, audio_size as usize)?;
346 self.asize += audio_size;
347 if (self.src.tell() & 1) == 1 {
348 if let Ok(0) = self.src.peek_byte() {
349 self.src.read_skip(1)?;
354 self.src.read_skip((size - 0x30) as usize)?;
357 self.src.read_skip(size as usize)?;
361 self.src.read_skip(size as usize)?;
364 if (self.src.tell() & 1) == 1 {
365 if let Ok(0) = self.src.peek_byte() {
366 self.src.read_skip(1)?;
371 fn get_frame_sanm(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
373 if self.src.tell() >= self.frme_end {
374 if !self.chunks.is_empty() {
375 let mut buf = Vec::new();
376 std::mem::swap(&mut self.chunks, &mut buf);
377 let stream = strmgr.get_stream(0).unwrap();
378 let ts = stream.make_ts(Some(self.cur_frame as u64 - 1), None, None);
379 return Ok(NAPacket::new(stream, ts, self.keyframe, buf));
381 if self.cur_frame == self.nframes {
382 return Err(DemuxerError::EOF);
384 let tag = self.src.read_tag()?;
385 let size = u64::from(self.src.read_u32be()?);
386 self.frme_end = self.src.tell() + size;
388 b"FLHD" => { self.keyframe = true; },
389 b"FRME" => { self.keyframe = false; },
391 self.src.read_skip(size as usize)?;
402 let tag = self.src.read_tag()?;
403 if self.src.tell() >= self.frme_end { // happens after some Wave tags
406 let size = u64::from(self.src.read_u32be()?);
407 let tend = self.src.tell() + size;
408 validate!(tend <= self.frme_end);
411 self.queue_chunk(tag, size as usize)?;
414 if let Some(stream) = strmgr.get_stream(1) {
415 let mut buf = [0; 12];
416 let mut nsamples = 0;
418 self.src.peek_buf(&mut buf)?;
419 nsamples = read_u32be(&buf[0..])?;
420 if nsamples == 0xFFFFFFFF {
421 nsamples = read_u32be(&buf[8..])?;
425 let mut ts = stream.make_ts(None, None, None);
427 ts.pts = Some(self.asize);
428 self.asize += u64::from(nsamples);
430 let pkt = self.src.read_packet(stream, ts, true, size as usize)?;
433 self.src.read_skip(size as usize)?;
437 //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);
438 self.src.read_skip(size as usize)?;
445 impl<'a> DemuxCore<'a> for SmushDemuxer<'a> {
446 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
447 let magic = self.src.read_tag()?;
455 _ => return Err(DemuxerError::InvalidData),
457 self.size = u64::from(self.src.read_u32be()?);
459 self.parse_anim_header(strmgr)?;
461 self.parse_sanm_header(strmgr)?;
468 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
469 if self.cur_frame > self.nframes { return Err(DemuxerError::EOF); }
471 self.get_frame_anim(strmgr)
473 self.get_frame_sanm(strmgr)
477 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
478 Err(DemuxerError::NotPossible)
480 fn get_duration(&self) -> u64 { 0 }
483 impl<'a> NAOptionHandler for SmushDemuxer<'a> {
484 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
485 fn set_options(&mut self, _options: &[NAOption]) { }
486 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
489 pub struct SmushDemuxerCreator { }
491 impl DemuxerCreator for SmushDemuxerCreator {
492 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
493 Box::new(SmushDemuxer::new(br))
495 fn get_name(&self) -> &'static str { "smush" }
499 struct MCMPDemuxer<'a> {
500 src: &'a mut ByteReader<'a>,
509 impl<'a> MCMPDemuxer<'a> {
510 fn new(io: &'a mut ByteReader<'a>) -> Self {
523 impl<'a> DemuxCore<'a> for MCMPDemuxer<'a> {
524 fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
525 let magic = self.src.read_tag()?;
526 validate!(&magic == b"MCMP");
527 let nframes = self.src.read_u16be()? as usize;
528 validate!(nframes > 1);
529 let cmp = self.src.read_byte()?;
530 let size1 = self.src.read_u32be()?;
531 let hdr_size = self.src.read_u32be()?;
532 validate!(cmp == 0 && size1 == hdr_size);
534 let size = (nframes - 1) as usize;
535 self.offsets = Vec::with_capacity(size);
536 self.sizes = Vec::with_capacity(size);
537 self.samples = Vec::with_capacity(size);
538 self.pts = Vec::with_capacity(size);
542 for _ in 1..nframes {
543 let compr = self.src.read_byte()?;
545 return Err(DemuxerError::NotImplemented);
547 let samples = self.src.read_u32be()? / 2;
548 let size = self.src.read_u32be()?;
549 self.offsets.push(start);
550 self.sizes.push(size);
551 self.samples.push(samples);
554 start += u64::from(size);
555 pts += u64::from(samples);
558 let codecs_desc_size = self.src.read_u16be()? as usize;
559 // todo check it's NULL+VIMA
560 self.src.read_skip(codecs_desc_size)?;
561 let data_start = self.src.tell() + u64::from(hdr_size);
565 if let Ok([b'R', b'I', b'F', b'F']) = self.src.peek_tag() {
566 validate!(hdr_size >= 44);
567 self.src.read_skip(22)?;
568 let c = self.src.read_u16le()?;
569 validate!(c == 1 || c == 2);
571 arate = self.src.read_u32le()?;
572 validate!(arate > 0);
574 parse_iact(self.src, data_start, &mut arate, &mut abits, &mut chans, true)?;
577 for (samp, pts) in self.samples.iter_mut().zip(self.pts.iter_mut()) {
578 validate!((*samp & 1) == 0);
585 let ahdr = NAAudioInfo::new(arate, chans, SND_S16_FORMAT, 0);
586 let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None);
587 if strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, arate, pts)).is_none() {
588 return Err(DemuxerError::MemoryError);
591 seek_index.mode = SeekIndexMode::Present;
592 seek_index.add_stream(0);
593 let index = seek_index.get_stream_index(0).unwrap();
594 for (i, (off, &pts)) in self.offsets.iter_mut().zip(self.pts.iter()).enumerate() {
596 index.add_entry(SeekEntry { time: pts * 1000 / u64::from(arate), pts, pos: i as u64 });
604 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
605 let idx = self.cur_frame;
606 if idx >= self.offsets.len() { return Err(DemuxerError::EOF); }
607 self.src.seek(SeekFrom::Start(self.offsets[idx]))?;
608 let mut buf = vec![0; self.sizes[idx] as usize + 4];
609 write_u32be(&mut buf, self.samples[idx])?;
610 self.src.read_buf(&mut buf[4..])?;
612 let stream = strmgr.get_stream(0).unwrap();
613 let ts = stream.make_ts(Some(self.pts[idx]), None, None);
617 Ok(NAPacket::new(stream, ts, true, buf))
620 fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
621 if let Some(ret) = seek_index.find_pos(time) {
622 self.cur_frame = ret.pos as usize;
625 Err(DemuxerError::SeekError)
628 fn get_duration(&self) -> u64 { 0 }
631 impl<'a> NAOptionHandler for MCMPDemuxer<'a> {
632 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
633 fn set_options(&mut self, _options: &[NAOption]) { }
634 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
637 pub struct MCMPDemuxerCreator { }
639 impl DemuxerCreator for MCMPDemuxerCreator {
640 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
641 Box::new(MCMPDemuxer::new(br))
643 fn get_name(&self) -> &'static str { "smush-mcmp" }
653 fn test_smush_demux_anim_v1() {
654 // sample from Rebel Assault game
655 let mut file = File::open("assets/Game/smush/c1block.anm").unwrap();
656 let mut fr = FileReader::new_read(&mut file);
657 let mut br = ByteReader::new(&mut fr);
658 let mut dmx = SmushDemuxer::new(&mut br);
659 let mut sm = StreamManager::new();
660 let mut si = SeekIndex::new();
661 dmx.open(&mut sm, &mut si).unwrap();
663 let pktres = dmx.get_frame(&mut sm);
664 if let Err(e) = pktres {
665 if (e as i32) == (DemuxerError::EOF as i32) { break; }
668 let pkt = pktres.unwrap();
669 println!("Got {}", pkt);
673 fn test_smush_demux_anim_v2() {
674 // sample from The Dig
675 let mut file = File::open("assets/Game/smush/PIGOUT.SAN").unwrap();
676 let mut fr = FileReader::new_read(&mut file);
677 let mut br = ByteReader::new(&mut fr);
678 let mut dmx = SmushDemuxer::new(&mut br);
679 let mut sm = StreamManager::new();
680 let mut si = SeekIndex::new();
681 dmx.open(&mut sm, &mut si).unwrap();
683 let pktres = dmx.get_frame(&mut sm);
684 if let Err(e) = pktres {
685 if (e as i32) == (DemuxerError::EOF as i32) { break; }
688 let pkt = pktres.unwrap();
689 println!("Got {}", pkt);
693 fn test_smush_demux_sanm() {
694 // sample from Grim Fandango
695 let mut file = File::open("assets/Game/smush/lol.snm").unwrap();
696 let mut fr = FileReader::new_read(&mut file);
697 let mut br = ByteReader::new(&mut fr);
698 let mut dmx = SmushDemuxer::new(&mut br);
699 let mut sm = StreamManager::new();
700 let mut si = SeekIndex::new();
701 dmx.open(&mut sm, &mut si).unwrap();
703 let pktres = dmx.get_frame(&mut sm);
704 if let Err(e) = pktres {
705 if (e as i32) == (DemuxerError::EOF as i32) { break; }
708 let pkt = pktres.unwrap();
709 println!("Got {}", pkt);
713 fn test_mcmp_demux_imus() {
714 // sample from Grim Fandango
715 let mut file = File::open("assets/Game/smush/1104 - Lupe.IMC").unwrap();
716 let mut fr = FileReader::new_read(&mut file);
717 let mut br = ByteReader::new(&mut fr);
718 let mut dmx = MCMPDemuxer::new(&mut br);
719 let mut sm = StreamManager::new();
720 let mut si = SeekIndex::new();
721 dmx.open(&mut sm, &mut si).unwrap();
723 let pktres = dmx.get_frame(&mut sm);
724 if let Err(e) = pktres {
725 if (e as i32) == (DemuxerError::EOF as i32) { break; }
728 let pkt = pktres.unwrap();
729 println!("Got {}", pkt);
733 fn test_mcmp_demux_wav() {
734 // sample from Grim Fandango
735 let mut file = File::open("assets/Game/smush/breadpor.WAV").unwrap();
736 let mut fr = FileReader::new_read(&mut file);
737 let mut br = ByteReader::new(&mut fr);
738 let mut dmx = MCMPDemuxer::new(&mut br);
739 let mut sm = StreamManager::new();
740 let mut si = SeekIndex::new();
741 dmx.open(&mut sm, &mut si).unwrap();
743 let pktres = dmx.get_frame(&mut sm);
744 if let Err(e) = pktres {
745 if (e as i32) == (DemuxerError::EOF as i32) { break; }
748 let pkt = pktres.unwrap();
749 println!("Got {}", pkt);