add LinePack decoder
[nihav.git] / nihav-game / src / codecs / imax.rs
CommitLineData
3813fe8a
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3
4const FRAME_W: usize = 320;
5const FRAME_H: usize = 160;
6
7struct IMAXDecoder {
8 info: NACodecInfoRef,
9 pal: [u8; 768],
10 frame: [u8; FRAME_W * FRAME_H],
11 hist: [u8; 32768],
12 hist_pos: usize,
13}
14
15impl IMAXDecoder {
16 fn new() -> Self {
17 Self {
18 info: NACodecInfoRef::default(),
19 pal: [0; 768],
20 frame: [0; FRAME_W * FRAME_H],
21 hist: [0; 32768],
22 hist_pos: 0,
23 }
24 }
25}
26
27impl NADecoder for IMAXDecoder {
28 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
29 if let NACodecTypeInfo::Video(_vinfo) = info.get_properties() {
30 /*let fmt = NAPixelFormaton::new(ColorModel::RGB(RGBSubmodel::RGB),
31 Some(NAPixelChromaton::new(0, 0, true, 8, 0, 0, 3)),
32 Some(NAPixelChromaton::new(0, 0, true, 8, 0, 1, 3)),
33 Some(NAPixelChromaton::new(0, 0, true, 8, 0, 2, 3)),
34 None, None,
35 FORMATON_FLAG_PALETTE, 3);*/
36 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(FRAME_W, FRAME_H, false, PAL8_FORMAT));
37 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
38
39 Ok(())
40 } else {
41 Err(DecoderError::InvalidData)
42 }
43 }
44 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
45 let src = pkt.get_buffer();
46 validate!(src.len() > 0);
47
48 for sd in pkt.side_data.iter() {
49 if let NASideData::Palette(true, ref pal) = sd {
50 for (dst, src) in self.pal.chunks_mut(3).zip(pal.chunks(4)) {
51 dst[0] = src[0];
52 dst[1] = src[1];
53 dst[2] = src[2];
54 }
55 break;
56 }
57 }
58
59 let mut mr = MemoryReader::new_read(&src);
60 let mut br = ByteReader::new(&mut mr);
61
62 let mut is_intra = true;
63 let mut is_skip = true;
64 let mut idx = 0;
65 while idx < self.frame.len() {
66 let v = br.read_byte()?;
67 let op = v >> 6;
68 let len = (v & 0x3F) as usize;
69 match op {
70 0 => {
71 validate!(idx + len <= self.frame.len());
72 idx += len;
73 is_intra = false;
74 },
75 1 => {
76 if len == 0 {
77 let off = br.read_u16le()? as usize;
78 let len = br.read_byte()? as usize;
79 validate!(idx + len <= self.frame.len());
80 validate!(off + len <= self.hist.len());
81 self.frame[idx..][..len].copy_from_slice(&self.hist[off..][..len]);
82 } else {
83 validate!(idx + len <= self.frame.len());
84 br.read_buf(&mut self.frame[idx..][..len])?;
85 if self.hist_pos + len <= self.hist.len() {
86 self.hist[self.hist_pos..][..len].copy_from_slice(&self.frame[idx..][..len]);
87 self.hist_pos += len;
88 }
89 idx += len;
90 }
91 is_skip = false;
92 },
93 2 => {
94 let pix = br.read_byte()?;
95 validate!(idx + len <= self.frame.len());
96 for _ in 0..len {
97 self.frame[idx] = pix;
98 idx += 1;
99 }
100 is_skip = false;
101 },
102 _ => {
103 let len2 = br.read_byte()? as usize;
104 let skip_len = len * 64 + len2;
105 validate!(idx + skip_len <= self.frame.len());
106 idx += skip_len;
107 is_intra = false;
108 },
109 };
110 }
111
112 let bufinfo = if !is_skip {
113 let binfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
114 let mut vbuf = binfo.get_vbuf().unwrap();
115 let paloff = vbuf.get_offset(1);
116 let stride = vbuf.get_stride(0);
117 let data = vbuf.get_data_mut().unwrap();
118 for (drow, srow) in data.chunks_mut(stride).zip(self.frame.chunks(FRAME_W)) {
119 drow[..FRAME_W].copy_from_slice(srow);
120 }
121 data[paloff..][..768].copy_from_slice(&self.pal);
122 binfo
123 } else {
124 NABufferType::None
125 };
126
127 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
128 frm.set_keyframe(is_intra);
129 let ftype = if is_skip { FrameType::Skip } else if is_intra { FrameType::I } else { FrameType::P };
130 frm.set_frame_type(ftype);
131 Ok(frm.into_ref())
132 }
133 fn flush(&mut self) {
134 }
135}
136
137impl NAOptionHandler for IMAXDecoder {
138 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
139 fn set_options(&mut self, _options: &[NAOption]) { }
140 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
141}
142
143pub fn get_decoder() -> Box<dyn NADecoder + Send> {
144 Box::new(IMAXDecoder::new())
145}
146
147#[cfg(test)]
148mod test {
149 use nihav_core::codecs::RegisteredDecoders;
150 use nihav_core::demuxers::RegisteredDemuxers;
151 use nihav_codec_support::test::dec_video::*;
152 use crate::game_register_all_decoders;
153 use crate::game_register_all_demuxers;
154 #[test]
155 fn test_imax_video() {
156 let mut dmx_reg = RegisteredDemuxers::new();
157 game_register_all_demuxers(&mut dmx_reg);
158 let mut dec_reg = RegisteredDecoders::new();
159 game_register_all_decoders(&mut dec_reg);
160
886cde48 161 // sample from Fable game
3813fe8a
KS
162 test_decoding("fable-imax", "fable-imax", "assets/Game/present.imx",
163 Some(64), &dmx_reg, &dec_reg,
164 ExpectedTestResult::MD5([0x775e1326, 0x7aa63674, 0x9b8aec54, 0x5caee2e3]));
165 }
166}