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 (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));
295 if self.cur_frame == self.nframes {
296 return Err(DemuxerError::EOF);
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;
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);
314 b"STOR" | b"FTCH" | b"NPAL" | b"XPAL" | b"FOBJ" => {
315 self.queue_chunk(tag, size as usize)?;
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);
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..])?;
331 if (self.src.tell() & 1) == 1 {
332 if let Ok(0) = self.src.peek_byte() {
333 self.src.read_skip(1)?;
336 return Ok(NAPacket::new(stream, ts, true, buf));
339 self.src.read_skip((size as usize) - 4)?;
343 self.src.read_skip(0x30)?;
344 if let Some(stream) = strmgr.get_stream(1) {
345 let (tb_num, tb_den) = stream.get_timebase();
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)?;
358 self.src.read_skip((size - 0x30) as usize)?;
361 self.src.read_skip(size as usize)?;
365 self.src.read_skip(size as usize)?;
368 if (self.src.tell() & 1) == 1 {
369 if let Ok(0) = self.src.peek_byte() {
370 self.src.read_skip(1)?;
375 fn get_frame_sanm(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
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));
386 if self.cur_frame == self.nframes {
387 return Err(DemuxerError::EOF);
389 let tag = self.src.read_tag()?;
390 let size = u64::from(self.src.read_u32be()?);
391 self.frme_end = self.src.tell() + size;
393 b"FLHD" => { self.keyframe = true; },
394 b"FRME" => { self.keyframe = false; },
396 self.src.read_skip(size as usize)?;
407 let tag = self.src.read_tag()?;
408 if self.src.tell() >= self.frme_end { // happens after some Wave tags
411 let size = u64::from(self.src.read_u32be()?);
412 let tend = self.src.tell() + size;
413 validate!(tend <= self.frme_end);
416 self.queue_chunk(tag, size as usize)?;
419 if let Some(stream) = strmgr.get_stream(1) {
420 let mut buf = [0; 12];
421 let mut nsamples = 0;
423 self.src.peek_buf(&mut buf)?;
424 nsamples = read_u32be(&buf[0..])?;
425 if nsamples == 0xFFFFFFFF {
426 nsamples = read_u32be(&buf[8..])?;
430 let (tb_num, tb_den) = stream.get_timebase();
431 let mut ts = NATimeInfo::new(None, None, None, tb_num, tb_den);
433 ts.pts = Some(self.asize);
434 self.asize += u64::from(nsamples);
436 let pkt = self.src.read_packet(stream, ts, true, size as usize)?;
439 self.src.read_skip(size as usize)?;
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)?;
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()?;
461 _ => return Err(DemuxerError::InvalidData),
463 self.size = u64::from(self.src.read_u32be()?);
465 self.parse_anim_header(strmgr)?;
467 self.parse_sanm_header(strmgr)?;
474 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
475 if self.cur_frame > self.nframes { return Err(DemuxerError::EOF); }
477 self.get_frame_anim(strmgr)
479 self.get_frame_sanm(strmgr)
483 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
484 Err(DemuxerError::NotPossible)
486 fn get_duration(&self) -> u64 { 0 }
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 }
495 pub struct SmushDemuxerCreator { }
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))
501 fn get_name(&self) -> &'static str { "smush" }
505 struct MCMPDemuxer<'a> {
506 src: &'a mut ByteReader<'a>,
515 impl<'a> MCMPDemuxer<'a> {
516 fn new(io: &'a mut ByteReader<'a>) -> Self {
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);
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);
548 for _ in 1..nframes {
549 let compr = self.src.read_byte()?;
551 return Err(DemuxerError::NotImplemented);
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);
560 start += u64::from(size);
561 pts += u64::from(samples);
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);
571 if let Ok([b'R', b'I', b'F', b'F']) = self.src.peek_tag() {
572 validate!(hdr_size >= 44);
573 self.src.read_skip(22)?;
574 let c = self.src.read_u16le()?;
575 validate!(c == 1 || c == 2);
577 arate = self.src.read_u32le()?;
578 validate!(arate > 0);
580 parse_iact(&mut self.src, data_start, &mut arate, &mut abits, &mut chans, true)?;
583 for (samp, pts) in self.samples.iter_mut().zip(self.pts.iter_mut()) {
584 validate!((*samp & 1) == 0);
591 let ahdr = NAAudioInfo::new(arate, chans, SND_S16_FORMAT, 0);
592 let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None);
593 if strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, arate, pts)).is_none() {
594 return Err(DemuxerError::MemoryError);
597 seek_index.mode = SeekIndexMode::Present;
598 seek_index.add_stream(0);
599 let index = seek_index.get_stream_index(0).unwrap();
600 for (i, (off, &pts)) in self.offsets.iter_mut().zip(self.pts.iter()).enumerate() {
602 index.add_entry(SeekEntry { time: pts * 1000 / u64::from(arate), pts, pos: i as u64 });
610 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
611 let idx = self.cur_frame;
612 if idx >= self.offsets.len() { return Err(DemuxerError::EOF); }
613 self.src.seek(SeekFrom::Start(self.offsets[idx]))?;
614 let mut buf = vec![0; self.sizes[idx] as usize + 4];
615 write_u32be(&mut buf, self.samples[idx])?;
616 self.src.read_buf(&mut buf[4..])?;
618 let stream = strmgr.get_stream(0).unwrap();
619 let (tb_num, tb_den) = stream.get_timebase();
620 let ts = NATimeInfo::new(Some(self.pts[idx]), None, None, tb_num, tb_den);
624 Ok(NAPacket::new(stream, ts, true, buf))
627 fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
628 if let Some(ret) = seek_index.find_pos(time) {
629 self.cur_frame = ret.pos as usize;
632 Err(DemuxerError::SeekError)
635 fn get_duration(&self) -> u64 { 0 }
638 impl<'a> NAOptionHandler for MCMPDemuxer<'a> {
639 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
640 fn set_options(&mut self, _options: &[NAOption]) { }
641 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
644 pub struct MCMPDemuxerCreator { }
646 impl DemuxerCreator for MCMPDemuxerCreator {
647 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
648 Box::new(MCMPDemuxer::new(br))
650 fn get_name(&self) -> &'static str { "smush-mcmp" }
660 fn test_smush_demux_anim_v1() {
661 // sample from Rebel Assault game
662 let mut file = File::open("assets/Game/smush/c1block.anm").unwrap();
663 let mut fr = FileReader::new_read(&mut file);
664 let mut br = ByteReader::new(&mut fr);
665 let mut dmx = SmushDemuxer::new(&mut br);
666 let mut sm = StreamManager::new();
667 let mut si = SeekIndex::new();
668 dmx.open(&mut sm, &mut si).unwrap();
670 let pktres = dmx.get_frame(&mut sm);
671 if let Err(e) = pktres {
672 if (e as i32) == (DemuxerError::EOF as i32) { break; }
675 let pkt = pktres.unwrap();
676 println!("Got {}", pkt);
680 fn test_smush_demux_anim_v2() {
681 // sample from The Dig
682 let mut file = File::open("assets/Game/smush/PIGOUT.SAN").unwrap();
683 let mut fr = FileReader::new_read(&mut file);
684 let mut br = ByteReader::new(&mut fr);
685 let mut dmx = SmushDemuxer::new(&mut br);
686 let mut sm = StreamManager::new();
687 let mut si = SeekIndex::new();
688 dmx.open(&mut sm, &mut si).unwrap();
690 let pktres = dmx.get_frame(&mut sm);
691 if let Err(e) = pktres {
692 if (e as i32) == (DemuxerError::EOF as i32) { break; }
695 let pkt = pktres.unwrap();
696 println!("Got {}", pkt);
700 fn test_smush_demux_sanm() {
701 // sample from Grim Fandango
702 let mut file = File::open("assets/Game/smush/lol.snm").unwrap();
703 let mut fr = FileReader::new_read(&mut file);
704 let mut br = ByteReader::new(&mut fr);
705 let mut dmx = SmushDemuxer::new(&mut br);
706 let mut sm = StreamManager::new();
707 let mut si = SeekIndex::new();
708 dmx.open(&mut sm, &mut si).unwrap();
710 let pktres = dmx.get_frame(&mut sm);
711 if let Err(e) = pktres {
712 if (e as i32) == (DemuxerError::EOF as i32) { break; }
715 let pkt = pktres.unwrap();
716 println!("Got {}", pkt);
720 fn test_mcmp_demux_imus() {
721 // sample from Grim Fandango
722 let mut file = File::open("assets/Game/smush/1104 - Lupe.IMC").unwrap();
723 let mut fr = FileReader::new_read(&mut file);
724 let mut br = ByteReader::new(&mut fr);
725 let mut dmx = MCMPDemuxer::new(&mut br);
726 let mut sm = StreamManager::new();
727 let mut si = SeekIndex::new();
728 dmx.open(&mut sm, &mut si).unwrap();
730 let pktres = dmx.get_frame(&mut sm);
731 if let Err(e) = pktres {
732 if (e as i32) == (DemuxerError::EOF as i32) { break; }
735 let pkt = pktres.unwrap();
736 println!("Got {}", pkt);
740 fn test_mcmp_demux_wav() {
741 // sample from Grim Fandango
742 let mut file = File::open("assets/Game/smush/breadpor.WAV").unwrap();
743 let mut fr = FileReader::new_read(&mut file);
744 let mut br = ByteReader::new(&mut fr);
745 let mut dmx = MCMPDemuxer::new(&mut br);
746 let mut sm = StreamManager::new();
747 let mut si = SeekIndex::new();
748 dmx.open(&mut sm, &mut si).unwrap();
750 let pktres = dmx.get_frame(&mut sm);
751 if let Err(e) = pktres {
752 if (e as i32) == (DemuxerError::EOF as i32) { break; }
755 let pkt = pktres.unwrap();
756 println!("Got {}", pkt);