add LinePack decoder
[nihav.git] / nihav-game / src / demuxers / imax.rs
CommitLineData
3813fe8a
KS
1use nihav_core::frame::*;
2use nihav_core::demuxers::*;
3use std::sync::Arc;
4
5#[allow(dead_code)]
6struct IMAXDemuxer<'a> {
7 src: &'a mut ByteReader<'a>,
8 cur_frame: u64,
9 apos: u64,
10 a_id: usize,
11 v_id: usize,
12 pal: Arc<[u8; 1024]>,
13 pal_change: bool,
14}
15
16impl<'a> DemuxCore<'a> for IMAXDemuxer<'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"IMAX");
23 let nframes = u64::from(src.read_u32le()?);
24 let fps = u32::from(src.read_u16le()?);
25 let magic2 = src.read_u16le()?;
26 validate!(magic2 == 0x102);
27 let _zero = src.read_u16le()?;
28 let _max_vframe_size = src.read_u32le()?;
29 let _buffering_size = src.read_u32le()?;
30
31 let vhdr = NAVideoInfo::new(320, 160, false, PAL8_FORMAT);
32 let vci = NACodecTypeInfo::Video(vhdr);
33 let vinfo = NACodecInfo::new("fable-imax", vci, None);
34 self.v_id = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, fps, nframes)).unwrap();
35 let ahdr = NAAudioInfo::new(22050, 1, SND_U8_FORMAT, 2);
36 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
37 self.a_id = strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, 22050, 2)).unwrap();
38 self.cur_frame = 0;
39 self.apos = 0;
40 Ok(())
41 }
42
43 #[allow(unused_variables)]
44 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
45 loop {
46 let fsize = self.src.read_u32le()? as usize;
47 let ftype = self.src.read_u32le()?;
48
49 match ftype {
50 0xAA97 => {
817e4872
KS
51 let stream = strmgr.get_stream(self.v_id).unwrap();
52 let ts = stream.make_ts(Some(self.cur_frame), None, None);
3813fe8a 53 self.cur_frame += 1;
817e4872 54 let mut pkt = self.src.read_packet(stream, ts, true, fsize)?;
3813fe8a
KS
55 pkt.add_side_data(NASideData::Palette(self.pal_change, self.pal.clone()));
56 self.pal_change = false;
57 return Ok(pkt);
58 },
59 0xAA98 => {
60 validate!(fsize == 768);
61 let mut pal = [0u8; 1024];
62 for chunk in pal.chunks_mut(4) {
63 let r = self.src.read_byte()?;
64 let g = self.src.read_byte()?;
65 let b = self.src.read_byte()?;
66 chunk[0] = (r << 2) | (r >> 4);
67 chunk[1] = (g << 2) | (g >> 4);
68 chunk[2] = (b << 2) | (b >> 4);
69 }
70 self.pal = Arc::new(pal);
71 self.pal_change = true;
72 },
73 0xAA99 => {
817e4872
KS
74 let stream = strmgr.get_stream(self.a_id).unwrap();
75 let ts = stream.make_ts(Some(self.apos), None, None);
3813fe8a 76 self.apos += fsize as u64;
817e4872 77 return self.src.read_packet(stream, ts, true, fsize);
3813fe8a
KS
78 },
79 0xAAFF => return Err(DemuxerError::EOF),
80 _ => return Err(DemuxerError::InvalidData),
81 }
82 }
83 }
84
85 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
86 Err(DemuxerError::NotPossible)
87 }
88 fn get_duration(&self) -> u64 { 0 }
89}
90impl<'a> NAOptionHandler for IMAXDemuxer<'a> {
91 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
92 fn set_options(&mut self, _options: &[NAOption]) { }
93 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
94}
95impl<'a> IMAXDemuxer<'a> {
96 fn new(io: &'a mut ByteReader<'a>) -> Self {
97 IMAXDemuxer {
98 src: io,
99 cur_frame: 0,
100 apos: 0,
101 a_id: 0,
102 v_id: 0,
103 pal: Arc::new([0; 1024]),
104 pal_change: false,
105 }
106 }
107}
108
109pub struct IMAXDemuxerCreator { }
110
111impl DemuxerCreator for IMAXDemuxerCreator {
112 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
113 Box::new(IMAXDemuxer::new(br))
114 }
115 fn get_name(&self) -> &'static str { "fable-imax" }
116}
117
118#[cfg(test)]
119mod test {
120 use super::*;
121 use std::fs::File;
122
123 #[test]
124 fn test_imax_demux() {
886cde48 125 // sample from Fable game
3813fe8a
KS
126 let mut file = File::open("assets/Game/present.imx").unwrap();
127 let mut fr = FileReader::new_read(&mut file);
128 let mut br = ByteReader::new(&mut fr);
129 let mut dmx = IMAXDemuxer::new(&mut br);
130 let mut sm = StreamManager::new();
131 let mut si = SeekIndex::new();
132 dmx.open(&mut sm, &mut si).unwrap();
133 loop {
134 let pktres = dmx.get_frame(&mut sm);
135 if let Err(e) = pktres {
136 if (e as i32) == (DemuxerError::EOF as i32) { break; }
137 panic!("error");
138 }
139 let pkt = pktres.unwrap();
140 println!("Got {}", pkt);
141 }
142 }
143}