| 1 | use nihav_core::codecs::*; |
| 2 | use nihav_core::io::bitreader::*; |
| 3 | use nihav_codec_support::codecs::imaadpcm::*; |
| 4 | use std::str::FromStr; |
| 5 | |
| 6 | const VIMA_STEPS: [&[i8]; 4] = [ |
| 7 | /*&[ -1, 4, -1, 4 ], |
| 8 | &[ -1, -1, 2, 6, -1, -1, 2, 6 ],*/ |
| 9 | &[ -1, -1, -1, -1, 1, 2, 4, 6, -1, -1, -1, -1, 1, 2, 4, 6 ], |
| 10 | &[ -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 2, 2, 4, 5, 6, |
| 11 | -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 2, 2, 4, 5, 6 ], |
| 12 | &[ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 13 | 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 5, 5, 6, 6, |
| 14 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 15 | 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 5, 5, 6, 6 ], |
| 16 | &[ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 17 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 18 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, |
| 19 | 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, |
| 20 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 21 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 22 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, |
| 23 | 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6 ] |
| 24 | ]; |
| 25 | |
| 26 | const STEP_TO_BITS: [u8; 89] = [ |
| 27 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 28 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 29 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 30 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| 31 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 32 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 |
| 33 | ]; |
| 34 | |
| 35 | struct VIMADecoder { |
| 36 | ainfo: NAAudioInfo, |
| 37 | chmap: NAChannelMap, |
| 38 | } |
| 39 | |
| 40 | impl VIMADecoder { |
| 41 | fn new() -> Self { |
| 42 | Self { |
| 43 | ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0), |
| 44 | chmap: NAChannelMap::new(), |
| 45 | } |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | impl NADecoder for VIMADecoder { |
| 50 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 51 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
| 52 | let channels = ainfo.get_channels(); |
| 53 | validate!(channels == 1 || channels == 2); |
| 54 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels, SND_S16P_FORMAT, 1); |
| 55 | self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap(); |
| 56 | Ok(()) |
| 57 | } else { |
| 58 | Err(DecoderError::InvalidData) |
| 59 | } |
| 60 | } |
| 61 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 62 | let info = pkt.get_stream().get_info(); |
| 63 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { |
| 64 | let src = pkt.get_buffer(); |
| 65 | validate!(src.len() > 4); |
| 66 | |
| 67 | let mut br = BitReader::new(&src, BitReaderMode::BE); |
| 68 | let mut samples = br.read(32)? as usize; |
| 69 | if samples == 0xFFFFFFFF { |
| 70 | br.skip(32)?; |
| 71 | samples = br.read(32)? as usize; |
| 72 | } |
| 73 | |
| 74 | let mut steps = [0; 2]; |
| 75 | steps[0] = br.read(8)? as usize; |
| 76 | let stereo = (steps[0] & 0x80) != 0; |
| 77 | validate!(!stereo || (self.chmap.num_channels() == 2)); |
| 78 | if stereo { |
| 79 | steps[0] ^= 0xFF; |
| 80 | } |
| 81 | validate!(steps[0] <= (IMA_MAX_STEP as usize)); |
| 82 | |
| 83 | let mut predictor = [0; 2]; |
| 84 | predictor[0] = br.read_s(16)?; |
| 85 | if stereo { |
| 86 | steps[1] = br.read(8)? as usize; |
| 87 | validate!(steps[1] <= (IMA_MAX_STEP as usize)); |
| 88 | predictor[1] = br.read_s(16)?; |
| 89 | } |
| 90 | |
| 91 | let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?; |
| 92 | let mut adata = abuf.get_abuf_i16().unwrap(); |
| 93 | let offset = adata.get_offset(1); |
| 94 | let adata = adata.get_data_mut().unwrap(); |
| 95 | let (l, r) = adata.split_at_mut(offset); |
| 96 | |
| 97 | for (ch_no, ch) in [l, r].iter_mut().take(if stereo { 2 } else { 1 }).enumerate() { |
| 98 | let mut step = steps[ch_no]; |
| 99 | let mut sample = predictor[ch_no]; |
| 100 | |
| 101 | for dst in ch.iter_mut().take(samples) { |
| 102 | let bits = STEP_TO_BITS[step]; |
| 103 | let mask = 1 << (bits - 1); |
| 104 | |
| 105 | let idx = br.read(bits)? as u8; |
| 106 | |
| 107 | sample = if (idx & !mask) != (mask - 1) { |
| 108 | let sign = (idx & mask) != 0; |
| 109 | let aidx = idx & !mask; |
| 110 | |
| 111 | let mut diff = (i32::from(2 * aidx + 1) * IMA_STEP_TABLE[step]) >> (bits - 1); |
| 112 | if sign { |
| 113 | diff = -diff; |
| 114 | } |
| 115 | |
| 116 | (sample + diff).max(-32768).min(32767) |
| 117 | } else { |
| 118 | br.read_s(16)? |
| 119 | }; |
| 120 | step = ((step as i8) + VIMA_STEPS[(bits - 4) as usize][idx as usize]).max(0).min(IMA_MAX_STEP as i8) as usize; |
| 121 | *dst = sample as i16; |
| 122 | } |
| 123 | } |
| 124 | if !stereo && self.chmap.num_channels() == 2 { |
| 125 | let (l, r) = adata.split_at_mut(offset); |
| 126 | r[..samples].copy_from_slice(l); |
| 127 | } |
| 128 | |
| 129 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); |
| 130 | frm.set_duration(Some(samples as u64)); |
| 131 | frm.set_keyframe(true); |
| 132 | Ok(frm.into_ref()) |
| 133 | } else { |
| 134 | Err(DecoderError::InvalidData) |
| 135 | } |
| 136 | } |
| 137 | fn flush(&mut self) { |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | impl NAOptionHandler for VIMADecoder { |
| 142 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } |
| 143 | fn set_options(&mut self, _options: &[NAOption]) { } |
| 144 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } |
| 145 | } |
| 146 | |
| 147 | pub fn get_decoder_vima() -> Box<dyn NADecoder + Send> { |
| 148 | Box::new(VIMADecoder::new()) |
| 149 | } |
| 150 | |
| 151 | #[cfg(test)] |
| 152 | mod test { |
| 153 | use nihav_core::codecs::RegisteredDecoders; |
| 154 | use nihav_core::demuxers::RegisteredDemuxers; |
| 155 | use nihav_codec_support::test::dec_video::*; |
| 156 | use crate::game_register_all_decoders; |
| 157 | use crate::game_register_all_demuxers; |
| 158 | #[test] |
| 159 | fn test_smush_vima() { |
| 160 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 161 | game_register_all_demuxers(&mut dmx_reg); |
| 162 | let mut dec_reg = RegisteredDecoders::new(); |
| 163 | game_register_all_decoders(&mut dec_reg); |
| 164 | |
| 165 | // samples from Grim Fandango |
| 166 | test_decoding("smush", "smush-vima", "assets/Game/smush/lol.snm", Some(75000), &dmx_reg, &dec_reg, |
| 167 | ExpectedTestResult::MD5([0xddd5dce1, 0xd5dc353c, 0xba176be8, 0x5afade63])); |
| 168 | test_decoding("smush", "smush-vima", "assets/Game/smush/ac_bu.snm", None, &dmx_reg, &dec_reg, |
| 169 | ExpectedTestResult::MD5([0x97a548e7, 0xb22d082b, 0x14c4110b, 0x9723891f])); |
| 170 | test_decoding("smush-mcmp", "smush-vima", "assets/Game/smush/1104 - Lupe.IMC", None, &dmx_reg, &dec_reg, |
| 171 | ExpectedTestResult::MD5([0x78389e65, 0xd99458a9, 0x6c62904e, 0xcaf732ba])); |
| 172 | } |
| 173 | } |
| 174 | |