Fable IMAX video support
[nihav.git] / nihav-game / src / demuxers / imax.rs
1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
3 use std::sync::Arc;
4
5 #[allow(dead_code)]
6 struct 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
16 impl<'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 => {
51 let str = strmgr.get_stream(self.v_id).unwrap();
52 let (tb_num, tb_den) = str.get_timebase();
53 let ts = NATimeInfo::new(Some(self.cur_frame), None, None, tb_num, tb_den);
54 self.cur_frame += 1;
55 let mut pkt = self.src.read_packet(str, ts, true, fsize)?;
56 pkt.add_side_data(NASideData::Palette(self.pal_change, self.pal.clone()));
57 self.pal_change = false;
58 return Ok(pkt);
59 },
60 0xAA98 => {
61 validate!(fsize == 768);
62 let mut pal = [0u8; 1024];
63 for chunk in pal.chunks_mut(4) {
64 let r = self.src.read_byte()?;
65 let g = self.src.read_byte()?;
66 let b = self.src.read_byte()?;
67 chunk[0] = (r << 2) | (r >> 4);
68 chunk[1] = (g << 2) | (g >> 4);
69 chunk[2] = (b << 2) | (b >> 4);
70 }
71 self.pal = Arc::new(pal);
72 self.pal_change = true;
73 },
74 0xAA99 => {
75 let str = strmgr.get_stream(self.a_id).unwrap();
76 let (tb_num, tb_den) = str.get_timebase();
77 let ts = NATimeInfo::new(Some(self.apos), None, None, tb_num, tb_den);
78 self.apos += fsize as u64;
79 return self.src.read_packet(str, ts, true, fsize);
80 },
81 0xAAFF => return Err(DemuxerError::EOF),
82 _ => return Err(DemuxerError::InvalidData),
83 }
84 }
85 }
86
87 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
88 Err(DemuxerError::NotPossible)
89 }
90 fn get_duration(&self) -> u64 { 0 }
91 }
92 impl<'a> NAOptionHandler for IMAXDemuxer<'a> {
93 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
94 fn set_options(&mut self, _options: &[NAOption]) { }
95 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
96 }
97 impl<'a> IMAXDemuxer<'a> {
98 fn new(io: &'a mut ByteReader<'a>) -> Self {
99 IMAXDemuxer {
100 src: io,
101 cur_frame: 0,
102 apos: 0,
103 a_id: 0,
104 v_id: 0,
105 pal: Arc::new([0; 1024]),
106 pal_change: false,
107 }
108 }
109 }
110
111 pub struct IMAXDemuxerCreator { }
112
113 impl DemuxerCreator for IMAXDemuxerCreator {
114 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
115 Box::new(IMAXDemuxer::new(br))
116 }
117 fn get_name(&self) -> &'static str { "fable-imax" }
118 }
119
120 #[cfg(test)]
121 mod test {
122 use super::*;
123 use std::fs::File;
124
125 #[test]
126 fn test_imax_demux() {
127 let mut file = File::open("assets/Game/present.imx").unwrap();
128 let mut fr = FileReader::new_read(&mut file);
129 let mut br = ByteReader::new(&mut fr);
130 let mut dmx = IMAXDemuxer::new(&mut br);
131 let mut sm = StreamManager::new();
132 let mut si = SeekIndex::new();
133 dmx.open(&mut sm, &mut si).unwrap();
134 loop {
135 let pktres = dmx.get_frame(&mut sm);
136 if let Err(e) = pktres {
137 if (e as i32) == (DemuxerError::EOF as i32) { break; }
138 panic!("error");
139 }
140 let pkt = pktres.unwrap();
141 println!("Got {}", pkt);
142 }
143 }
144 }