]>
Commit | Line | Data |
---|---|---|
8d91d85f KS |
1 | use nihav_core::frame::*; |
2 | use nihav_core::formats; | |
f1b0db38 | 3 | #[cfg(feature="decoder_fstaud")] |
8d91d85f KS |
4 | use nihav_core::formats::NAChannelMap; |
5 | use nihav_core::codecs::*; | |
f1b0db38 | 6 | #[cfg(feature="decoder_fstvid")] |
8d91d85f | 7 | use nihav_core::io::byteio::*; |
f1b0db38 | 8 | #[cfg(feature="decoder_fstaud")] |
8d91d85f KS |
9 | use nihav_codec_support::codecs::imaadpcm::IMAState; |
10 | ||
f1b0db38 | 11 | #[cfg(feature="decoder_fstvid")] |
8d91d85f KS |
12 | struct FutureVisionVideoDecoder { |
13 | info: NACodecInfoRef, | |
14 | pal: [u8; 768], | |
15 | frame: Vec<u8>, | |
16 | w: usize, | |
17 | h: usize, | |
18 | } | |
19 | ||
f1b0db38 | 20 | #[cfg(feature="decoder_fstvid")] |
8d91d85f KS |
21 | struct Bits8<'a> { |
22 | src: &'a [u8], | |
23 | pos: usize, | |
24 | buf: u8, | |
25 | bit: u8, | |
26 | } | |
27 | ||
f1b0db38 | 28 | #[cfg(feature="decoder_fstvid")] |
8d91d85f KS |
29 | impl<'a> Bits8<'a> { |
30 | fn new(src: &'a [u8]) -> Self { Bits8 { src, pos: 0, buf: 0, bit: 0 } } | |
31 | fn read_bit(&mut self) -> ByteIOResult<bool> { | |
32 | if self.bit == 0 { | |
33 | if self.pos < self.src.len() { | |
34 | self.buf = self.src[self.pos]; | |
35 | self.pos += 1; | |
36 | self.bit = 8; | |
37 | } else { | |
38 | return Err(ByteIOError::ReadError); | |
39 | } | |
40 | } | |
41 | let bit = (self.buf & 0x80) != 0; | |
42 | self.buf <<= 1; | |
43 | self.bit -= 1; | |
44 | Ok(bit) | |
45 | } | |
46 | } | |
47 | ||
f1b0db38 | 48 | #[cfg(feature="decoder_fstvid")] |
8d91d85f KS |
49 | impl FutureVisionVideoDecoder { |
50 | fn new() -> Self { | |
51 | FutureVisionVideoDecoder { | |
52 | info: NACodecInfoRef::default(), | |
53 | pal: [0; 768], | |
54 | frame: Vec::new(), | |
55 | w: 0, | |
56 | h: 0, | |
57 | } | |
58 | } | |
59 | ||
60 | fn output_frame(&mut self, bufinfo: &mut NABufferType, w: usize, h: usize) { | |
61 | let bufo = bufinfo.get_vbuf(); | |
62 | let mut buf = bufo.unwrap(); | |
63 | let paloff = buf.get_offset(1); | |
64 | let stride = buf.get_stride(0); | |
65 | let data = buf.get_data_mut().unwrap(); | |
66 | let dst = data.as_mut_slice(); | |
67 | ||
68 | dst[paloff..][..768].copy_from_slice(&self.pal); | |
69 | for (dline, sline) in dst.chunks_mut(stride).zip(self.frame.chunks(w)).take(h) { | |
70 | dline[..w].copy_from_slice(sline); | |
71 | } | |
72 | } | |
73 | } | |
74 | ||
f1b0db38 | 75 | #[cfg(feature="decoder_fstvid")] |
8d91d85f KS |
76 | impl NADecoder for FutureVisionVideoDecoder { |
77 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
78 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
79 | let w = vinfo.get_width(); | |
80 | let h = vinfo.get_height(); | |
81 | validate!((w & 1) == 0 && (h & 1) == 0); | |
82 | let fmt = PAL8_FORMAT; | |
83 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt)); | |
84 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
85 | self.w = w; | |
86 | self.h = h; | |
87 | ||
88 | self.frame.resize(w * h, 0); | |
89 | self.pal = [0; 768]; | |
90 | Ok(()) | |
91 | } else { | |
92 | Err(DecoderError::InvalidData) | |
93 | } | |
94 | } | |
95 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
96 | let src = pkt.get_buffer(); | |
97 | validate!(src.len() >= 4); | |
98 | ||
99 | let bitsize = read_u16le(&src)? as usize; | |
100 | let bsize = (bitsize + 8) >> 3; | |
101 | validate!(bsize + 2 <= src.len()); | |
102 | ||
103 | let mut flags = Bits8::new(&src[2..][..bsize]); | |
104 | let mut mr = MemoryReader::new_read(&src[2 + bsize..]); | |
105 | let mut br = ByteReader::new(&mut mr); | |
106 | ||
107 | if (bsize + 2 != src.len()) && flags.read_bit()? { | |
108 | for dst in self.pal.iter_mut() { | |
109 | let b = br.read_byte()?; | |
110 | *dst = (b << 2) | (b >> 4); | |
111 | } | |
112 | } | |
113 | ||
114 | let mut is_intra = true; | |
115 | let stride = self.w; | |
116 | // for some reason last row should not be decoded | |
117 | for row4 in self.frame.chunks_mut(stride * 4).take(self.h / 4 - 1) { | |
118 | for x in (0..self.w).step_by(4) { | |
119 | if flags.read_bit()? { | |
120 | if flags.read_bit()? { | |
121 | let c0 = br.read_byte()?; | |
122 | let c1 = br.read_byte()?; | |
123 | let mut mask = br.read_u16le()?; | |
124 | for dst in row4[x..].chunks_mut(stride) { | |
125 | for pix in dst.iter_mut().take(4) { | |
126 | *pix = if (mask & 0x8000) != 0 { c1 } else { c0 }; | |
127 | mask <<= 1; | |
128 | } | |
129 | } | |
130 | } else { | |
131 | for dst in row4[x..].chunks_mut(stride) { | |
132 | br.read_buf(&mut dst[..4])?; | |
133 | } | |
134 | } | |
135 | } else { | |
136 | is_intra = false; | |
137 | } | |
138 | } | |
139 | } | |
140 | ||
141 | let mut bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?; | |
142 | ||
143 | self.output_frame(&mut bufinfo, self.w, self.h); | |
144 | ||
145 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
146 | frm.set_keyframe(is_intra); | |
147 | frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); | |
148 | Ok(frm.into_ref()) | |
149 | } | |
150 | fn flush(&mut self) { | |
151 | } | |
152 | } | |
153 | ||
f1b0db38 | 154 | #[cfg(feature="decoder_fstvid")] |
8d91d85f KS |
155 | impl NAOptionHandler for FutureVisionVideoDecoder { |
156 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
157 | fn set_options(&mut self, _options: &[NAOption]) { } | |
158 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
159 | } | |
160 | ||
f1b0db38 | 161 | #[cfg(feature="decoder_fstvid")] |
8d91d85f KS |
162 | pub fn get_decoder_video() -> Box<dyn NADecoder + Send> { |
163 | Box::new(FutureVisionVideoDecoder::new()) | |
164 | } | |
165 | ||
f1b0db38 | 166 | #[cfg(feature="decoder_fstaud")] |
8d91d85f KS |
167 | struct FutureVisionAudioDecoder { |
168 | ainfo: NAAudioInfo, | |
169 | chmap: NAChannelMap, | |
170 | state: IMAState, | |
171 | count: usize, | |
172 | } | |
173 | ||
f1b0db38 | 174 | #[cfg(feature="decoder_fstaud")] |
8d91d85f KS |
175 | impl FutureVisionAudioDecoder { |
176 | fn new() -> Self { | |
177 | FutureVisionAudioDecoder { | |
178 | ainfo: NAAudioInfo::new(0, 1, formats::SND_S16_FORMAT, 0), | |
179 | chmap: NAChannelMap::from_ms_mapping(0x4), //single channel | |
180 | state: IMAState::new(), | |
181 | count: 0, | |
182 | } | |
183 | } | |
184 | } | |
185 | ||
f1b0db38 | 186 | #[cfg(feature="decoder_fstaud")] |
8d91d85f KS |
187 | impl NADecoder for FutureVisionAudioDecoder { |
188 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
189 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { | |
190 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), 1, formats::SND_S16P_FORMAT, 1); | |
191 | Ok(()) | |
192 | } else { | |
193 | Err(DecoderError::InvalidData) | |
194 | } | |
195 | } | |
196 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
197 | let info = pkt.get_stream().get_info(); | |
198 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
199 | let pktbuf = pkt.get_buffer(); | |
200 | let samples = pktbuf.len() * 2; | |
201 | let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?; | |
202 | let mut adata = abuf.get_abuf_i16().unwrap(); | |
203 | let buf = adata.get_data_mut().unwrap(); | |
204 | for (dst, &val) in buf.chunks_exact_mut(2).zip(pktbuf.iter()) { | |
205 | dst[0] = self.state.expand_sample(val & 0xF); | |
206 | dst[1] = self.state.expand_sample(val >> 4); | |
207 | if self.count < 50 { | |
208 | dst[0] = 0; | |
209 | dst[1] = 0; | |
210 | } | |
211 | self.count += 2; | |
212 | } | |
213 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); | |
214 | frm.set_duration(Some(samples as u64)); | |
215 | frm.set_keyframe(false); | |
216 | Ok(frm.into_ref()) | |
217 | } else { | |
218 | Err(DecoderError::InvalidData) | |
219 | } | |
220 | } | |
221 | fn flush(&mut self) { | |
222 | } | |
223 | } | |
224 | ||
f1b0db38 | 225 | #[cfg(feature="decoder_fstaud")] |
8d91d85f KS |
226 | impl NAOptionHandler for FutureVisionAudioDecoder { |
227 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
228 | fn set_options(&mut self, _options: &[NAOption]) { } | |
229 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
230 | } | |
231 | ||
f1b0db38 | 232 | #[cfg(feature="decoder_fstaud")] |
8d91d85f KS |
233 | pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> { |
234 | Box::new(FutureVisionAudioDecoder::new()) | |
235 | } | |
236 | ||
237 | #[cfg(test)] | |
238 | mod test { | |
239 | use nihav_core::codecs::RegisteredDecoders; | |
240 | use nihav_core::demuxers::RegisteredDemuxers; | |
241 | use nihav_codec_support::test::dec_video::*; | |
242 | use crate::game_register_all_decoders; | |
243 | use crate::game_register_all_demuxers; | |
244 | ||
886cde48 | 245 | // samples come from the Harvester game |
8d91d85f KS |
246 | #[test] |
247 | fn test_fst_video() { | |
248 | let mut dmx_reg = RegisteredDemuxers::new(); | |
249 | game_register_all_demuxers(&mut dmx_reg); | |
250 | let mut dec_reg = RegisteredDecoders::new(); | |
251 | game_register_all_decoders(&mut dec_reg); | |
252 | ||
253 | test_decoding("fst", "fst-video", "assets/Game/alarm.fst", None, &dmx_reg, &dec_reg, | |
254 | ExpectedTestResult::MD5([0x4028440a, 0xcb8aed5b, 0x2a9f1ead, 0x269169f5])); | |
255 | } | |
256 | #[test] | |
257 | fn test_fst_audio() { | |
258 | let mut dmx_reg = RegisteredDemuxers::new(); | |
259 | game_register_all_demuxers(&mut dmx_reg); | |
260 | let mut dec_reg = RegisteredDecoders::new(); | |
261 | game_register_all_decoders(&mut dec_reg); | |
262 | ||
263 | test_decoding("fcmp", "fst-audio", "assets/Game/anxiety.cmp", None, &dmx_reg, &dec_reg, | |
264 | ExpectedTestResult::MD5([0xa45b65b3, 0xe0654352, 0xf553e90b, 0x5dce0023])); | |
265 | } | |
266 | } |