FutureVision game formats support
[nihav.git] / nihav-game / src / demuxers / fst.rs
1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
3
4 #[allow(dead_code)]
5 struct FutureVisionVideoDemuxer<'a> {
6 src: &'a mut ByteReader<'a>,
7 cur_frame: usize,
8 apos: u64,
9 vsize: Vec<usize>,
10 asize: Vec<usize>,
11 a_id: Option<usize>,
12 v_id: Option<usize>,
13 vframe: bool,
14 }
15
16 impl<'a> DemuxCore<'a> for FutureVisionVideoDemuxer<'a> {
17 #[allow(unused_variables)]
18 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
19 let src = &mut self.src;
20
21 let magic = src.read_tag()?;
22 validate!(&magic == b"2TSF");
23 let width = src.read_u32le()? as usize;
24 let height = src.read_u32le()? as usize;
25 validate!(width != 0 && height != 0);
26 let _flags = src.read_u32le()?;
27 let nframes = src.read_u32le()? as usize;
28 let fps = src.read_u32le()?;
29 let arate = src.read_u32le()?;
30 let abits = src.read_u32le()?;
31
32 let vhdr = NAVideoInfo::new(width, height, false, PAL8_FORMAT);
33 let vci = NACodecTypeInfo::Video(vhdr);
34 let vinfo = NACodecInfo::new("fst-video", vci, None);
35 self.v_id = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, fps, nframes as u64));
36 if arate != 0 {
37 validate!(abits == 8 || abits == 16);
38 let ahdr = NAAudioInfo::new(arate, 1, if abits == 16 { SND_S16_FORMAT } else { SND_U8_FORMAT }, 2);
39 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
40 self.a_id = strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, arate, 2));
41 }
42 self.vsize = Vec::with_capacity(nframes);
43 self.asize = Vec::with_capacity(nframes);
44 for _ in 0..nframes {
45 let vsize = src.read_u32le()? as usize;
46 let asize = src.read_u16le()? as usize;
47 self.vsize.push(vsize);
48 self.asize.push(asize);
49 }
50 self.vframe = true;
51 self.cur_frame = 0;
52 self.apos = 0;
53 Ok(())
54 }
55
56 #[allow(unused_variables)]
57 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
58 if self.cur_frame >= self.vsize.len() { return Err(DemuxerError::EOF); }
59 let (id, size, pts) = if self.vframe {
60 self.vframe = self.a_id.is_none();
61
62 (self.v_id.unwrap_or(0), self.vsize[self.cur_frame], self.cur_frame as u64)
63 } else {
64 self.vframe = true;
65 let apos = self.apos;
66 self.apos += (self.asize[self.cur_frame] as u64) * 2;
67
68 (self.a_id.unwrap_or(0), self.asize[self.cur_frame], apos)
69 };
70
71 if self.vframe {
72 self.cur_frame += 1;
73 }
74
75 let str = strmgr.get_stream(id).unwrap();
76 let (tb_num, tb_den) = str.get_timebase();
77 let ts = NATimeInfo::new(Some(pts), None, None, tb_num, tb_den);
78 self.src.read_packet(str, ts, true, size)
79 }
80
81 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
82 Err(DemuxerError::NotPossible)
83 }
84 fn get_duration(&self) -> u64 { 0 }
85 }
86 impl<'a> NAOptionHandler for FutureVisionVideoDemuxer<'a> {
87 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
88 fn set_options(&mut self, _options: &[NAOption]) { }
89 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
90 }
91 impl<'a> FutureVisionVideoDemuxer<'a> {
92 fn new(io: &'a mut ByteReader<'a>) -> Self {
93 FutureVisionVideoDemuxer {
94 src: io,
95 cur_frame: 0,
96 apos: 0,
97 vsize: Vec::new(),
98 asize: Vec::new(),
99 a_id: None,
100 v_id: None,
101 vframe: false,
102 }
103 }
104 }
105
106 pub struct FSTDemuxerCreator { }
107
108 impl DemuxerCreator for FSTDemuxerCreator {
109 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
110 Box::new(FutureVisionVideoDemuxer::new(br))
111 }
112 fn get_name(&self) -> &'static str { "fst" }
113 }
114
115 #[allow(dead_code)]
116 struct FutureVisionAudioDemuxer<'a> {
117 src: &'a mut ByteReader<'a>,
118 a_id: usize,
119 end: u64,
120 arate: u32,
121 }
122
123 impl<'a> DemuxCore<'a> for FutureVisionAudioDemuxer<'a> {
124 #[allow(unused_variables)]
125 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
126 let src = &mut self.src;
127
128 let magic = src.read_tag()?;
129 validate!(&magic == b"FCMP");
130 let size = u64::from(src.read_u32le()?);
131 let arate = src.read_u32le()?;
132 validate!(arate != 0);
133 let abits = src.read_u16le()?;
134 validate!(abits == 8 || abits == 16);
135
136 let ahdr = NAAudioInfo::new(arate, 1, if abits == 16 { SND_S16_FORMAT } else { SND_U8_FORMAT }, 2);
137 let ainfo = NACodecInfo::new("fst-audio", NACodecTypeInfo::Audio(ahdr), None);
138 self.a_id = strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, arate, 2)).unwrap();
139 self.end = self.src.tell() + size;
140 self.arate = arate;
141 Ok(())
142 }
143
144 #[allow(unused_variables)]
145 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
146 if self.src.tell() >= self.end { return Err(DemuxerError::EOF); }
147 let size = (self.end - self.src.tell()).min(0x2000) as usize;
148 let pts = (self.src.tell() - 14) * 2;
149
150 let str = strmgr.get_stream(self.a_id).unwrap();
151 let (tb_num, tb_den) = str.get_timebase();
152 let ts = NATimeInfo::new(Some(pts), None, None, tb_num, tb_den);
153 self.src.read_packet(str, ts, true, size)
154 }
155
156 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
157 Err(DemuxerError::NotPossible)
158 }
159 fn get_duration(&self) -> u64 { (self.end - 14) * 2000 / u64::from(self.arate) }
160 }
161 impl<'a> NAOptionHandler for FutureVisionAudioDemuxer<'a> {
162 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
163 fn set_options(&mut self, _options: &[NAOption]) { }
164 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
165 }
166 impl<'a> FutureVisionAudioDemuxer<'a> {
167 fn new(io: &'a mut ByteReader<'a>) -> Self {
168 FutureVisionAudioDemuxer {
169 src: io,
170 a_id: 0,
171 end: 0,
172 arate: 0,
173 }
174 }
175 }
176
177 pub struct FCMPDemuxerCreator { }
178
179 impl DemuxerCreator for FCMPDemuxerCreator {
180 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
181 Box::new(FutureVisionAudioDemuxer::new(br))
182 }
183 fn get_name(&self) -> &'static str { "fcmp" }
184 }
185
186 #[cfg(test)]
187 mod test {
188 use super::*;
189 use std::fs::File;
190
191 #[test]
192 fn test_fst_demux() {
193 let mut file = File::open("assets/Game/c007.fst").unwrap();
194 let mut fr = FileReader::new_read(&mut file);
195 let mut br = ByteReader::new(&mut fr);
196 let mut dmx = FutureVisionVideoDemuxer::new(&mut br);
197 let mut sm = StreamManager::new();
198 let mut si = SeekIndex::new();
199 dmx.open(&mut sm, &mut si).unwrap();
200 loop {
201 let pktres = dmx.get_frame(&mut sm);
202 if let Err(e) = pktres {
203 if (e as i32) == (DemuxerError::EOF as i32) { break; }
204 panic!("error");
205 }
206 let pkt = pktres.unwrap();
207 println!("Got {}", pkt);
208 }
209 }
210
211 #[test]
212 fn test_fcmp_demux() {
213 let mut file = File::open("assets/Game/anxiety.cmp").unwrap();
214 let mut fr = FileReader::new_read(&mut file);
215 let mut br = ByteReader::new(&mut fr);
216 let mut dmx = FutureVisionAudioDemuxer::new(&mut br);
217 let mut sm = StreamManager::new();
218 let mut si = SeekIndex::new();
219 dmx.open(&mut sm, &mut si).unwrap();
220 loop {
221 let pktres = dmx.get_frame(&mut sm);
222 if let Err(e) = pktres {
223 if (e as i32) == (DemuxerError::EOF as i32) { break; }
224 panic!("error");
225 }
226 let pkt = pktres.unwrap();
227 println!("Got {}", pkt);
228 }
229 }
230 }