]> git.nihav.org Git - nihav.git/blob - nihav-game/src/demuxers/seq.rs
Sierra RBT and SEQ formats support
[nihav.git] / nihav-game / src / demuxers / seq.rs
1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
3
4 struct SequenceDemuxer<'a> {
5 src: &'a mut ByteReader<'a>,
6 nframes: usize,
7 frame_no: usize,
8 }
9
10 impl<'a> DemuxCore<'a> for SequenceDemuxer<'a> {
11 #[allow(unused_variables)]
12 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
13 let src = &mut self.src;
14
15 self.nframes = src.read_u16le()? as usize;
16 validate!(self.nframes > 0);
17 let pal_size = src.read_u32le()? as usize;
18 validate!(pal_size > 37 && pal_size <= 1024 + 37);
19 let mut pal_chunk = vec![0; pal_size];
20 src.read_buf(&mut pal_chunk)?;
21
22 let vhdr = NAVideoInfo::new(320, 200, false, PAL8_FORMAT);
23 let vci = NACodecTypeInfo::Video(vhdr);
24 let vinfo = NACodecInfo::new("seq-video", vci, Some(pal_chunk));
25 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 10, self.nframes as u64)).is_none() {
26 return Err(DemuxerError::MemoryError);
27 }
28
29 self.frame_no = 0;
30 Ok(())
31 }
32
33 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
34 const FRAME_HEADER: usize = 24;
35
36 if self.frame_no == self.nframes {
37 return Err(DemuxerError::EOF);
38 }
39
40 let stream = strmgr.get_stream(0).unwrap();
41 let ts = stream.make_ts(Some(self.frame_no as u64), None, None);
42
43 let mut buf = vec![0; FRAME_HEADER];
44 self.src.read_buf(&mut buf)?;
45 let frm_size = read_u16le(&buf[12..])? as usize;
46 let offset = u64::from(self.src.read_u32le()?);
47 validate!(offset >= self.src.tell());
48 self.src.seek(SeekFrom::Start(offset))?;
49 buf.resize(FRAME_HEADER + frm_size, 0);
50 self.src.read_buf(&mut buf[FRAME_HEADER..])?;
51
52 self.frame_no += 1;
53
54 Ok(NAPacket::new(stream, ts, self.frame_no == 1, buf))
55 }
56
57 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
58 Err(DemuxerError::NotPossible)
59 }
60 fn get_duration(&self) -> u64 { 0 }
61 }
62 impl<'a> NAOptionHandler for SequenceDemuxer<'a> {
63 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
64 fn set_options(&mut self, _options: &[NAOption]) { }
65 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
66 }
67 impl<'a> SequenceDemuxer<'a> {
68 fn new(io: &'a mut ByteReader<'a>) -> Self {
69 SequenceDemuxer {
70 src: io,
71 frame_no: 0,
72 nframes: 0,
73 }
74 }
75 }
76
77 pub struct SequenceDemuxerCreator { }
78
79 impl DemuxerCreator for SequenceDemuxerCreator {
80 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
81 Box::new(SequenceDemuxer::new(br))
82 }
83 fn get_name(&self) -> &'static str { "sierra-seq" }
84 }
85
86 #[cfg(test)]
87 mod test {
88 use super::*;
89 use std::fs::File;
90
91 // sample from King's Quest VI
92 #[test]
93 fn test_seq() {
94 let mut file = File::open("assets/Game/sierra/FS1.SEQ").unwrap();
95 let mut fr = FileReader::new_read(&mut file);
96 let mut br = ByteReader::new(&mut fr);
97 let mut dmx = SequenceDemuxer::new(&mut br);
98 let mut sm = StreamManager::new();
99 let mut si = SeekIndex::new();
100 dmx.open(&mut sm, &mut si).unwrap();
101 loop {
102 let pktres = dmx.get_frame(&mut sm);
103 if let Err(e) = pktres {
104 if (e as i32) == (DemuxerError::EOF as i32) { break; }
105 panic!("error");
106 }
107 let pkt = pktres.unwrap();
108 println!("Got {}", pkt);
109 }
110 }
111 }