add LinePack decoder
[nihav.git] / nihav-game / src / demuxers / sga.rs
1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
3
4 const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
5 comp_info: [
6 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
7 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 1, next_elem: 2 }),
8 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 2, next_elem: 2 }),
9 None, None],
10 elem_size: 2, be: false, alpha: false, palette: false };
11 struct SGADemuxer<'a> {
12 src: &'a mut ByteReader<'a>,
13 subtype: u8,
14 apts: u64,
15 abuf: Vec<u8>,
16 abuf2: Vec<u8>,
17 asize: usize,
18 no_ts_in_f9: bool,
19 ntsc: bool,
20 }
21
22 impl<'a> SGADemuxer<'a> {
23 fn new(io: &'a mut ByteReader<'a>) -> Self {
24 Self {
25 src: io,
26 subtype: 0,
27 apts: 0,
28 abuf: Vec::new(),
29 abuf2: Vec::new(),
30 asize: 0,
31 no_ts_in_f9: false,
32 ntsc: false,
33 }
34 }
35 }
36
37 fn parse_smpte_time(src: &[u8], ntsc: bool) -> DemuxerResult<u64> {
38 validate!(src.len() >= 4);
39 let hours = src[0];
40 let minutes = src[1];
41 validate!(minutes < 60);
42 let seconds = src[2];
43 validate!(seconds < 60);
44 let frame = src[3];
45 if ntsc {
46 validate!(frame < 60);
47 } else {
48 validate!(frame < 30);
49 }
50
51 let tot_min = u64::from(hours) * 60 + u64::from(minutes);
52 let tot_sec = tot_min * 60 + u64::from(seconds);
53 Ok(tot_sec * if ntsc { 60 } else { 30 } + u64::from(frame))
54 }
55
56 fn get_smpte_time(src: &mut ByteReader, ntsc: bool) -> DemuxerResult<u64> {
57 let mut buf = [0; 4];
58 src.read_buf(&mut buf)?;
59 parse_smpte_time(&buf, ntsc)
60 }
61
62 impl<'a> DemuxCore<'a> for SGADemuxer<'a> {
63 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
64 let mut subtype = self.src.read_byte()?;
65 match subtype {
66 0xF1 => {
67 self.src.read_skip(3)?;
68 subtype = self.src.read_byte()?;
69 },
70 0xF4 => {
71 self.src.read_skip(1)?;
72 let csize = self.src.read_u16be()?;
73 self.src.read_skip(usize::from(csize))?;
74 subtype = self.src.read_byte()?;
75 },
76 0xF9 => {
77 self.src.read_skip(3)?;
78 if (self.src.peek_byte()? & 0x80) == 0 {
79 self.src.read_skip(4)?;
80 } else {
81 self.no_ts_in_f9 = true;
82 }
83 subtype = self.src.read_byte()?;
84 },
85 _ => {},
86 };
87 validate!(subtype >= 0x80);
88 if !matches!(subtype, 0x81 | 0x85 | 0x86 | 0x89 | 0x8A) {
89 return Err(DemuxerError::NotImplemented);
90 }
91 self.subtype = subtype;
92 match subtype {
93 0x81 | 0x8A => {
94 self.src.read_skip(9)?;
95 let tile_w = self.src.read_byte()?;
96 let tile_h = self.src.read_byte()?;
97 validate!(tile_w > 0 && tile_h > 0);
98 self.src.seek(SeekFrom::Start(0))?;
99 let vhdr = NAVideoInfo::new(usize::from(tile_w) * 8, usize::from(tile_h) * 8, false, RGB555_FORMAT);
100 let vci = NACodecTypeInfo::Video(vhdr);
101 let vinfo = NACodecInfo::new("dp-sga", vci, Some(vec![subtype]));
102 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 30, 0)).is_none() {
103 return Err(DemuxerError::MemoryError);
104 }
105 },
106 0x85 | 0x86 => {
107 let mut edata = vec![0; 0x201];
108 edata[0] = subtype;
109 self.src.read_byte()?;
110 let tile_w = self.src.read_byte()?;
111 let tile_h = self.src.read_byte()?;
112 validate!(tile_w > 0 && tile_h > 0);
113 self.src.read_skip(8)?;
114 self.src.read_buf(&mut edata[1..])?;
115 if self.subtype == 0x85 {
116 self.asize = usize::from(self.src.read_u16be()?);
117 }
118
119 let vhdr = NAVideoInfo::new(usize::from(tile_w) * 8, usize::from(tile_h) * 8, false, RGB555_FORMAT);
120 let vci = NACodecTypeInfo::Video(vhdr);
121 let vinfo = NACodecInfo::new("dp-sga", vci, Some(edata));
122 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 30, 0)).is_none() {
123 return Err(DemuxerError::MemoryError);
124 }
125
126 let srate = 16000;
127 let ahdr = NAAudioInfo::new(srate, 1, SND_U8_FORMAT, 1);
128 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
129 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, srate, 0)).is_none() {
130 return Err(DemuxerError::MemoryError);
131 }
132 },
133 0x89 => {
134 self.src.seek(SeekFrom::Start(0))?;
135 let vhdr = NAVideoInfo::new(256, 160, false, RGB555_FORMAT);
136 let vci = NACodecTypeInfo::Video(vhdr);
137 let vinfo = NACodecInfo::new("dp-sga", vci, Some(vec![subtype]));
138 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 30, 0)).is_none() {
139 return Err(DemuxerError::MemoryError);
140 }
141
142 let srate = 22050;
143 let ahdr = NAAudioInfo::new(srate, 1, SND_U8_FORMAT, 1);
144 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
145 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, srate, 0)).is_none() {
146 return Err(DemuxerError::MemoryError);
147 }
148 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
149 if strmgr.add_stream(NAStream::new(StreamType::Audio, 2, ainfo, 1, srate, 0)).is_none() {
150 return Err(DemuxerError::MemoryError);
151 }
152 },
153 _ => unreachable!(),
154 };
155
156 Ok(())
157 }
158
159 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
160 if !self.abuf.is_empty() {
161 let mut buf = Vec::new();
162 std::mem::swap(&mut buf, &mut self.abuf);
163
164 if let Some(stream) = strmgr.get_stream(1) {
165 let ts = stream.make_ts(Some(self.apts), None, None);
166 self.apts += buf.len() as u64;
167 return Ok(NAPacket::new(stream, ts, true, buf));
168 }
169 }
170 if !self.abuf2.is_empty() {
171 let mut buf = Vec::new();
172 std::mem::swap(&mut buf, &mut self.abuf2);
173
174 if let Some(stream) = strmgr.get_stream(2) {
175 let ts = stream.make_ts(Some(self.apts), None, None);
176 self.apts += buf.len() as u64;
177 return Ok(NAPacket::new(stream, ts, true, buf));
178 }
179 }
180 match self.subtype {
181 0x81 | 0x8A => {
182 let mut hdr = [0; 4];
183 loop {
184 match self.src.read_buf(&mut hdr) {
185 Ok(_) => {},
186 Err(ByteIOError::ReadError) |
187 Err(ByteIOError::EOF) => return Err(DemuxerError::EOF),
188 Err(err) => return Err(err.into()),
189 };
190 let chunk_size = usize::from(read_u16le(&hdr[2..])?);
191 validate!(chunk_size > 8);
192 match hdr[0] {
193 0x81 | 0x8A => {
194 let mut buf = vec![0; chunk_size + 4];
195 buf[..4].copy_from_slice(&hdr);
196 self.src.read_buf(&mut buf[4..])?;
197 let ts = parse_smpte_time(&buf[4..], self.ntsc)?;
198 let stream = strmgr.get_stream(0).unwrap();
199 let ts = NATimeInfo::new(Some(ts), None, None, stream.tb_num, stream.tb_den);
200 return Ok(NAPacket::new(stream, ts, false, buf));
201 },
202 0xF1 => {},
203 0xF9 => {
204 if !self.no_ts_in_f9 {
205 self.src.read_skip(4)?;
206 }
207 },
208 _ => self.src.read_skip(chunk_size)?,
209 };
210 if (self.src.tell() & 1) != 0 {
211 self.src.read_skip(1)?;
212 }
213 }
214 },
215 0x85 => {
216 let ts = match get_smpte_time(self.src, self.ntsc) {
217 Ok(val) => val,
218 Err(DemuxerError::IOError) => return Err(DemuxerError::EOF),
219 Err(err) => return Err(err),
220 };
221 let pal_size = self.src.read_u16be()?;
222 let asize = usize::from(self.src.read_u16be()?);
223 validate!(asize >= self.asize);
224 let full_size = usize::from(self.src.read_u16be()?);
225 validate!(full_size >= asize);
226 let pal_off = self.src.read_u16be()?;
227 let vsize = full_size - self.asize;
228 let offset = (asize - self.asize) as u16;
229 let mut buf = vec![0; vsize + 6];
230 if asize > 0 {
231 self.abuf.resize(self.asize - 1, 0);
232 self.src.read_buf(&mut self.abuf)?;
233 self.src.read_byte()?;
234 }
235 write_u16be(&mut buf, pal_off)?;
236 write_u16be(&mut buf[2..], pal_size)?;
237 write_u16be(&mut buf[4..], offset)?;
238 self.src.read_buf(&mut buf[6..])?;
239
240 let stream = strmgr.get_stream(0).unwrap();
241 let ts = NATimeInfo::new(Some(ts), None, None, stream.tb_num, stream.tb_den);
242 Ok(NAPacket::new(stream, ts, false, buf))
243 },
244 0x86 => {
245 let ts = match get_smpte_time(self.src, self.ntsc) {
246 Ok(val) => val,
247 Err(DemuxerError::IOError) => return Err(DemuxerError::EOF),
248 Err(err) => return Err(err),
249 };
250 let asize = usize::from(self.src.read_u16be()?);
251 let vsize = usize::from(self.src.read_u16be()?);
252 let pal_off = self.src.read_u16be()?;
253 let pal_size = self.src.read_u16be()?;
254 let offset = self.src.read_u16be()?;
255 let mut buf = vec![0; vsize + 6];
256 if asize > 0 {
257 self.abuf.resize(asize, 0);
258 self.src.read_buf(&mut self.abuf)?;
259 }
260 write_u16be(&mut buf, pal_off)?;
261 write_u16be(&mut buf[2..], pal_size)?;
262 write_u16be(&mut buf[4..], offset)?;
263 self.src.read_buf(&mut buf[6..])?;
264
265 let stream = strmgr.get_stream(0).unwrap();
266 let ts = NATimeInfo::new(Some(ts), None, None, stream.tb_num, stream.tb_den);
267 Ok(NAPacket::new(stream, ts, false, buf))
268 },
269 0x89 => {
270 let mut hdr = [0; 4];
271 loop {
272 match self.src.read_buf(&mut hdr) {
273 Ok(_) => {},
274 Err(ByteIOError::ReadError) |
275 Err(ByteIOError::EOF) => return Err(DemuxerError::EOF),
276 Err(err) => return Err(err.into()),
277 };
278 let chunk_size = usize::from(read_u16be(&hdr[2..])?);
279 validate!((hdr[0] & 0x80) != 0);
280 validate!(chunk_size > 8);
281 let end = self.src.tell() + (chunk_size as u64);
282 match hdr[0] {
283 0x89 => {
284 let ts = get_smpte_time(self.src, self.ntsc)?;
285 let asize = usize::from(self.src.read_u16be()?);
286 let vsize = usize::from(self.src.read_u16be()?);
287 validate!((asize & 0x7FFF) + vsize + 16 <= chunk_size);
288 let pal_size = self.src.read_u16be()?;
289 let offset = self.src.read_u16be()?;
290 validate!(usize::from(offset) <= vsize);
291 let mut buf = vec![0; vsize + 6];
292 if asize > 0 {
293 if (asize & 0x8000) == 0 {
294 self.abuf.resize(asize, 0);
295 self.src.read_buf(&mut self.abuf)?;
296 self.abuf2.resize(asize, 0);
297 self.abuf2.copy_from_slice(&self.abuf);
298 } else {
299 let asize = asize & 0x7FFF;
300 validate!((asize & 1) == 0);
301 self.abuf.resize(asize / 2, 0);
302 self.abuf2.resize(asize / 2, 0);
303 self.src.read_buf(&mut self.abuf)?;
304 self.src.read_buf(&mut self.abuf2)?;
305 }
306 }
307 write_u16be(&mut buf, 1/*pal_off*/)?;
308 write_u16be(&mut buf[2..], pal_size)?;
309 write_u16be(&mut buf[4..], offset)?;
310 self.src.read_buf(&mut buf[6..])?;
311 validate!(self.src.tell() <= end);
312 self.src.seek(SeekFrom::Start(end))?;
313
314 let stream = strmgr.get_stream(0).unwrap();
315 let ts = NATimeInfo::new(Some(ts), None, None, stream.tb_num, stream.tb_den);
316 return Ok(NAPacket::new(stream, ts, false, buf));
317 },
318 _ => self.src.read_skip(chunk_size)?,
319 };
320 }
321 },
322 _ => unreachable!(),
323 }
324 }
325
326 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
327 Err(DemuxerError::NotPossible)
328 }
329 fn get_duration(&self) -> u64 { 0 }
330 }
331
332 const DEMUXER_OPTS: &[NAOptionDefinition] = &[
333 NAOptionDefinition {
334 name: "ntsc", description: "timestamps are 60fps instead of 30fps",
335 opt_type: NAOptionDefinitionType::Bool },
336 ];
337
338 impl<'a> NAOptionHandler for SGADemuxer<'a> {
339 fn get_supported_options(&self) -> &[NAOptionDefinition] { DEMUXER_OPTS }
340 fn set_options(&mut self, options: &[NAOption]) {
341 for option in options.iter() {
342 for opt_def in DEMUXER_OPTS.iter() {
343 if opt_def.check(option).is_ok() {
344 if let ("name", NAValue::Bool(ref bval)) = (option.name, &option.value) {
345 self.ntsc = *bval;
346 }
347 }
348 }
349 }
350 }
351 fn query_option_value(&self, name: &str) -> Option<NAValue> {
352 match name {
353 "ntsc" => Some(NAValue::Bool(self.ntsc)),
354 _ => None,
355 }
356 }
357 }
358
359 pub struct SGADemuxerCreator { }
360
361 impl DemuxerCreator for SGADemuxerCreator {
362 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
363 Box::new(SGADemuxer::new(br))
364 }
365 fn get_name(&self) -> &'static str { "sga" }
366 }
367
368 #[cfg(test)]
369 mod test {
370 use super::*;
371 use std::fs::File;
372
373 fn test_sga_demux(name: &str) {
374 let mut file = File::open(name).unwrap();
375 let mut fr = FileReader::new_read(&mut file);
376 let mut br = ByteReader::new(&mut fr);
377 let mut dmx = SGADemuxer::new(&mut br);
378 let mut sm = StreamManager::new();
379 let mut si = SeekIndex::new();
380 dmx.open(&mut sm, &mut si).unwrap();
381 loop {
382 let pktres = dmx.get_frame(&mut sm);
383 if let Err(e) = pktres {
384 if e == DemuxerError::EOF { break; }
385 panic!("error");
386 }
387 let pkt = pktres.unwrap();
388 println!("Got {}", pkt);
389 }
390 }
391
392 #[test]
393 fn test_sga_demux_81() {
394 // samples from Double Switch game
395 test_sga_demux("assets/Game/sga/ALEXSTIL.AVC");
396 test_sga_demux("assets/Game/sga/DPLOGO.AVC");
397 }
398 #[test]
399 fn test_sga_demux_85() {
400 // sample from Night Trap game
401 test_sga_demux("assets/Game/sga/CRMOVIE");
402 }
403 #[test]
404 fn test_sga_demux_86() {
405 // sample from Corpse Killer game
406 test_sga_demux("assets/Game/sga/dplogo.dtv");
407 }
408 }