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) -> DemuxerResult<()> {
20 let tag = br.read_tag()?;
28 while br.tell() < end {
29 let tag = br.read_tag()?;
30 let size = u64::from(br.read_u32be()?);
33 let cend = br.tell() + size;
34 while br.tell() < cend {
35 let tag = br.read_tag()?;
36 let size = u64::from(br.read_u32be()?);
39 validate!(size == 20);
42 let bits = br.read_u32be()?;
43 validate!(bits > 0 && bits <= 16);
45 *arate = br.read_u32be()?;
46 let c = br.read_u32be()?;
47 validate!(c == 1 || c == 2);
51 _ => br.read_skip(size as usize)?,
55 b"DATA" => return Err(DemuxerError::InvalidData),
56 _ => br.read_skip(size as usize)?,
59 Err(DemuxerError::InvalidData)
62 impl<'a> SmushDemuxer<'a> {
63 fn new(io: &'a mut ByteReader<'a>) -> Self {
79 fn parse_anim_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
80 let src = &mut self.src;
82 let tag = src.read_tag()?;
83 validate!(&tag == b"AHDR");
84 let size = u64::from(src.read_u32be()?);
85 validate!(size >= 768 + 6);
86 let end = src.tell() + size;
87 validate!(end < self.size);
88 let version = src.read_u16le()?;
89 validate!(version < 3);
90 self.nframes = src.read_u16le()? as usize;
91 validate!(self.nframes != 0);
92 src.read_skip(2)?; //max FRME size
93 let mut edata = vec![0; 768 + 1];
94 edata[0] = version as u8;
95 src.read_buf(&mut edata[1..][..768])?;
96 src.read_skip(size as usize - 768 - 6)?;
98 let start = src.tell();
101 let tag = src.read_tag()?;
102 validate!(&tag == b"FRME");
103 size = u64::from(src.read_u32be()?);
106 let end = src.tell() + size;
107 validate!(end <= self.size + 8); // some NUTs feature slightly incorrect total size
116 while src.tell() < end {
117 let tag = src.read_tag()?;
118 let size = u64::from(src.read_u32be()?);
120 let tend = src.tell() + size;
121 validate!(tend <= end);
124 validate!(size >= 10);
125 let _codec = src.read_u16le()?;
126 let x = src.read_u16le()? as i16;
127 let y = src.read_u16le()? as i16;
128 if x == 0 && y == 0 && width == 0 && height == 0 {
129 width = src.read_u16le()? as usize;
130 height = src.read_u16le()? as usize;
132 let w = src.read_u16le()? as usize;
133 let h = src.read_u16le()? as usize;
134 if x == 0 && y == 0 && w >= width && h >= height {
139 src.read_skip((size - 10) as usize)?;
143 let end = src.tell() + size;
144 let opcode = src.read_u16le()?;
145 let flags = src.read_u16le()?;
146 if (opcode == 8) && (flags == 0x2E) {
147 if parse_iact(src, end, &mut arate, &mut abits, &mut chans).is_ok() {
148 aname = "smush-iact";
150 validate!(src.tell() <= end);
152 src.seek(SeekFrom::Start(end))?;
159 src.read_skip(size as usize)?;
161 _ => { src.read_skip(size as usize)?; },
163 if (src.tell() & 1) != 0 {
164 if let Ok(0) = src.peek_byte() {
170 width = width.max(320);
171 height = height.max(200);
172 src.seek(SeekFrom::Start(start))?;
173 self.frme_end = start;
175 let vhdr = NAVideoInfo::new(width, height, false, PAL8_FORMAT);
176 let vci = NACodecTypeInfo::Video(vhdr);
177 let vinfo = NACodecInfo::new("smushv1", vci, Some(edata));
178 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 15, self.nframes as u64)).is_none() {
179 return Err(DemuxerError::MemoryError);
182 if !aname.is_empty() {
183 validate!(arate > 0);
184 let mut fmt = SND_S16_FORMAT;
186 "pcm" => { fmt = SND_U8_FORMAT; },
187 "smush-iact" => { fmt.bits = abits; fmt.packed = true; },
190 let ahdr = NAAudioInfo::new(arate, chans, fmt, 0);
191 let ainfo = NACodecInfo::new(aname, NACodecTypeInfo::Audio(ahdr), None);
192 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, arate, 0)).is_none() {
193 return Err(DemuxerError::MemoryError);
199 fn parse_sanm_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
200 let src = &mut self.src;
202 let tag = src.read_tag()?;
203 validate!(&tag == b"SHDR");
204 let size = u64::from(src.read_u32be()?);
205 validate!(src.tell() + size <= self.size);
206 validate!(size >= 0x426);
208 let maj_ver = src.read_byte()?;
209 let min_ver = src.read_byte()?;
210 if maj_ver != 1 || min_ver != 0 {
211 return Err(DemuxerError::NotImplemented);
213 self.nframes = src.read_u16le()? as usize;
214 let _xoff = src.read_u16le()? as usize;
215 let _yoff = src.read_u16le()? as usize;
216 let width = src.read_u16le()? as usize;
217 let height = src.read_u16le()? as usize;
218 let _imgtype = src.read_u16le()?;
219 let frame_delay = src.read_u32le()?;
220 let _max_frame_size = src.read_u32le()?;
221 src.read_skip(1024)?; // palette
222 src.read_skip((size as usize) - 0x416)?;
224 let tag = src.read_tag()?;
225 validate!(&tag == b"FLHD");
226 let size = u64::from(src.read_u32be()?);
227 let end = src.tell() + size;
232 while src.tell() < end {
233 let tag = src.read_tag()?;
234 if src.tell() == end { break; }
235 let size = src.read_u32be()?;
238 validate!(size >= 8);
239 arate = src.read_u32le()?;
240 let cc = src.read_u32le()?;
241 validate!(cc == 1 || cc == 2);
244 alen = u64::from(src.read_u32le()? / cc / 2);
245 src.read_skip((size as usize) - 12)?;
248 _ => src.read_skip(size as usize)?,
251 validate!(src.tell() == end);
253 let vhdr = NAVideoInfo::new(width, height, false, RGB565_FORMAT);
254 let vci = NACodecTypeInfo::Video(vhdr);
255 let vinfo = NACodecInfo::new("smushv2", vci, None);
256 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, frame_delay, 1000000, self.nframes as u64)).is_none() {
257 return Err(DemuxerError::MemoryError);
260 let ahdr = NAAudioInfo::new(arate, chans, SND_S16P_FORMAT, 0);
261 let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None);
262 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, arate, alen)).is_none() {
263 return Err(DemuxerError::MemoryError);
270 fn queue_chunk(&mut self, tag: [u8; 4], size: usize) -> DemuxerResult<()> {
271 self.chunks.extend_from_slice(&tag);
272 let start = self.chunks.len();
273 let nlen = start + size + 4;
274 self.chunks.resize(nlen, 0);
275 write_u32be(&mut self.chunks[start..], size as u32).unwrap();
276 self.src.read_buf(&mut self.chunks[start + 4..])?;
279 fn get_frame_anim(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
281 if self.src.tell() >= self.frme_end {
282 if !self.chunks.is_empty() {
283 let mut buf = Vec::new();
284 std::mem::swap(&mut self.chunks, &mut buf);
285 let stream = strmgr.get_stream(0).unwrap();
286 let (tb_num, tb_den) = stream.get_timebase();
287 let ts = NATimeInfo::new(Some(self.cur_frame as u64 - 1), None, None, tb_num, tb_den);
288 return Ok(NAPacket::new(stream, ts, false, buf));
290 if self.cur_frame == self.nframes {
291 return Err(DemuxerError::EOF);
293 let tag = self.src.read_tag()?;
294 validate!(&tag == b"FRME");
295 let size = u64::from(self.src.read_u32be()?);
296 self.frme_end = self.src.tell() + size;
304 let tag = self.src.read_tag()?;
305 let size = u64::from(self.src.read_u32be()?);
306 let tend = self.src.tell() + size;
307 validate!(tend <= self.frme_end);
309 b"STOR" | b"FTCH" | b"NPAL" | b"XPAL" | b"FOBJ" => {
310 self.queue_chunk(tag, size as usize)?;
313 validate!(size >= 4);
314 let opcode = self.src.read_u16le()?;
315 let flags = self.src.read_u16le()?;
316 if (opcode == 8) && (flags == 0x2E) {
317 if let Some(stream) = strmgr.get_stream(1) {
318 let (tb_num, tb_den) = stream.get_timebase();
319 let ts = NATimeInfo::new(None, None, None, tb_num, tb_den);
321 let mut buf = vec![0; size as usize];
322 write_u16le(&mut buf[0..2], opcode).unwrap();
323 write_u16le(&mut buf[2..4], flags).unwrap();
324 self.src.read_buf(&mut buf[4..])?;
326 if (self.src.tell() & 1) == 1 {
327 if let Ok(0) = self.src.peek_byte() {
328 self.src.read_skip(1)?;
331 return Ok(NAPacket::new(stream, ts, true, buf));
334 self.src.read_skip((size as usize) - 4)?;
338 self.src.read_skip(0x30)?;
339 if let Some(stream) = strmgr.get_stream(1) {
340 let (tb_num, tb_den) = stream.get_timebase();
342 let audio_size = size - 0x30;
343 let ts = NATimeInfo::new(Some(self.asize), None, None, tb_num, tb_den);
344 let pkt = self.src.read_packet(stream, ts, true, audio_size as usize)?;
345 self.asize += audio_size;
346 if (self.src.tell() & 1) == 1 {
347 if let Ok(0) = self.src.peek_byte() {
348 self.src.read_skip(1)?;
353 self.src.read_skip((size - 0x30) as usize)?;
356 self.src.read_skip(size as usize)?;
360 self.src.read_skip(size as usize)?;
363 if (self.src.tell() & 1) == 1 {
364 if let Ok(0) = self.src.peek_byte() {
365 self.src.read_skip(1)?;
370 fn get_frame_sanm(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
372 if self.src.tell() >= self.frme_end {
373 if !self.chunks.is_empty() {
374 let mut buf = Vec::new();
375 std::mem::swap(&mut self.chunks, &mut buf);
376 let stream = strmgr.get_stream(0).unwrap();
377 let (tb_num, tb_den) = stream.get_timebase();
378 let ts = NATimeInfo::new(Some(self.cur_frame as u64 - 1), None, None, tb_num, tb_den);
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 (tb_num, tb_den) = stream.get_timebase();
426 let mut ts = NATimeInfo::new(None, None, None, tb_num, tb_den);
428 ts.pts = Some(self.asize);
429 self.asize += u64::from(nsamples);
431 let pkt = self.src.read_packet(stream, ts, true, size as usize)?;
434 self.src.read_skip(size as usize)?;
438 //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);
439 self.src.read_skip(size as usize)?;
446 impl<'a> DemuxCore<'a> for SmushDemuxer<'a> {
447 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
448 let magic = self.src.read_tag()?;
456 _ => return Err(DemuxerError::InvalidData),
458 self.size = u64::from(self.src.read_u32be()?);
460 self.parse_anim_header(strmgr)?;
462 self.parse_sanm_header(strmgr)?;
469 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
470 if self.cur_frame > self.nframes { return Err(DemuxerError::EOF); }
472 self.get_frame_anim(strmgr)
474 self.get_frame_sanm(strmgr)
478 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
479 Err(DemuxerError::NotPossible)
481 fn get_duration(&self) -> u64 { 0 }
484 impl<'a> NAOptionHandler for SmushDemuxer<'a> {
485 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
486 fn set_options(&mut self, _options: &[NAOption]) { }
487 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
490 pub struct SmushDemuxerCreator { }
492 impl DemuxerCreator for SmushDemuxerCreator {
493 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
494 Box::new(SmushDemuxer::new(br))
496 fn get_name(&self) -> &'static str { "smush" }
505 fn test_smush_demux_anim_v1() {
506 // sample from Rebel Assault game
507 let mut file = File::open("assets/Game/smush/c1block.anm").unwrap();
508 let mut fr = FileReader::new_read(&mut file);
509 let mut br = ByteReader::new(&mut fr);
510 let mut dmx = SmushDemuxer::new(&mut br);
511 let mut sm = StreamManager::new();
512 let mut si = SeekIndex::new();
513 dmx.open(&mut sm, &mut si).unwrap();
515 let pktres = dmx.get_frame(&mut sm);
516 if let Err(e) = pktres {
517 if (e as i32) == (DemuxerError::EOF as i32) { break; }
520 let pkt = pktres.unwrap();
521 println!("Got {}", pkt);
525 fn test_smush_demux_anim_v2() {
526 // sample from The Dig
527 let mut file = File::open("assets/Game/smush/PIGOUT.SAN").unwrap();
528 let mut fr = FileReader::new_read(&mut file);
529 let mut br = ByteReader::new(&mut fr);
530 let mut dmx = SmushDemuxer::new(&mut br);
531 let mut sm = StreamManager::new();
532 let mut si = SeekIndex::new();
533 dmx.open(&mut sm, &mut si).unwrap();
535 let pktres = dmx.get_frame(&mut sm);
536 if let Err(e) = pktres {
537 if (e as i32) == (DemuxerError::EOF as i32) { break; }
540 let pkt = pktres.unwrap();
541 println!("Got {}", pkt);
545 fn test_smush_demux_sanm() {
546 // sample from Grim Fandango
547 let mut file = File::open("assets/Game/smush/lol.snm").unwrap();
548 let mut fr = FileReader::new_read(&mut file);
549 let mut br = ByteReader::new(&mut fr);
550 let mut dmx = SmushDemuxer::new(&mut br);
551 let mut sm = StreamManager::new();
552 let mut si = SeekIndex::new();
553 dmx.open(&mut sm, &mut si).unwrap();
555 let pktres = dmx.get_frame(&mut sm);
556 if let Err(e) = pktres {
557 if (e as i32) == (DemuxerError::EOF as i32) { break; }
560 let pkt = pktres.unwrap();
561 println!("Got {}", pkt);