| 1 | use nihav_core::frame::*; |
| 2 | use nihav_core::formats; |
| 3 | #[cfg(feature="decoder_fstaud")] |
| 4 | use nihav_core::formats::NAChannelMap; |
| 5 | use nihav_core::codecs::*; |
| 6 | #[cfg(feature="decoder_fstvid")] |
| 7 | use nihav_core::io::byteio::*; |
| 8 | #[cfg(feature="decoder_fstaud")] |
| 9 | use nihav_codec_support::codecs::imaadpcm::IMAState; |
| 10 | |
| 11 | #[cfg(feature="decoder_fstvid")] |
| 12 | struct FutureVisionVideoDecoder { |
| 13 | info: NACodecInfoRef, |
| 14 | pal: [u8; 768], |
| 15 | frame: Vec<u8>, |
| 16 | w: usize, |
| 17 | h: usize, |
| 18 | } |
| 19 | |
| 20 | #[cfg(feature="decoder_fstvid")] |
| 21 | struct Bits8<'a> { |
| 22 | src: &'a [u8], |
| 23 | pos: usize, |
| 24 | buf: u8, |
| 25 | bit: u8, |
| 26 | } |
| 27 | |
| 28 | #[cfg(feature="decoder_fstvid")] |
| 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 | |
| 48 | #[cfg(feature="decoder_fstvid")] |
| 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 | |
| 75 | #[cfg(feature="decoder_fstvid")] |
| 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 | |
| 154 | #[cfg(feature="decoder_fstvid")] |
| 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 | |
| 161 | #[cfg(feature="decoder_fstvid")] |
| 162 | pub fn get_decoder_video() -> Box<dyn NADecoder + Send> { |
| 163 | Box::new(FutureVisionVideoDecoder::new()) |
| 164 | } |
| 165 | |
| 166 | #[cfg(feature="decoder_fstaud")] |
| 167 | struct FutureVisionAudioDecoder { |
| 168 | ainfo: NAAudioInfo, |
| 169 | chmap: NAChannelMap, |
| 170 | state: IMAState, |
| 171 | count: usize, |
| 172 | } |
| 173 | |
| 174 | #[cfg(feature="decoder_fstaud")] |
| 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 | |
| 186 | #[cfg(feature="decoder_fstaud")] |
| 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 | |
| 225 | #[cfg(feature="decoder_fstaud")] |
| 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 | |
| 232 | #[cfg(feature="decoder_fstaud")] |
| 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 | |
| 245 | // samples come from the Harvester game |
| 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 | } |