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