| 1 | use nihav_core::codecs::*; |
| 2 | use nihav_core::io::byteio::*; |
| 3 | use std::str::FromStr; |
| 4 | |
| 5 | struct IACTDecoder { |
| 6 | ainfo: NAAudioInfo, |
| 7 | chmap: NAChannelMap, |
| 8 | bits: u8, |
| 9 | tot_size: u32, |
| 10 | old: bool, |
| 11 | queued: Vec<u8>, |
| 12 | } |
| 13 | |
| 14 | impl IACTDecoder { |
| 15 | fn new() -> Self { |
| 16 | Self { |
| 17 | ainfo: NAAudioInfo::new(0, 1, SND_S16_FORMAT, 0), |
| 18 | chmap: NAChannelMap::new(), |
| 19 | bits: 0, |
| 20 | tot_size: 0, |
| 21 | old: false, |
| 22 | queued: Vec::new(), |
| 23 | } |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | impl NADecoder for IACTDecoder { |
| 28 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 29 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
| 30 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), SND_S16_FORMAT, 1); |
| 31 | self.chmap = NAChannelMap::from_str(if ainfo.get_channels() == 1 { "C" } else { "L,R" }).unwrap(); |
| 32 | self.bits = ainfo.get_format().bits; |
| 33 | Ok(()) |
| 34 | } else { |
| 35 | Err(DecoderError::InvalidData) |
| 36 | } |
| 37 | } |
| 38 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 39 | let info = pkt.get_stream().get_info(); |
| 40 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { |
| 41 | let src = pkt.get_buffer(); |
| 42 | validate!(src.len() > 18); |
| 43 | |
| 44 | let code = read_u16le(&src[0..])?; |
| 45 | let flags = read_u16le(&src[2..])?; |
| 46 | if code != 8 || flags != 0x2E { |
| 47 | let mut frm = NAFrame::new_from_pkt(pkt, info, NABufferType::None); |
| 48 | frm.set_duration(Some(0)); |
| 49 | frm.set_keyframe(true); |
| 50 | return Ok(frm.into_ref()); |
| 51 | } |
| 52 | let _left = read_u32le(&src[14..])?; |
| 53 | let offset = if self.tot_size == 0 { |
| 54 | let mut mr = MemoryReader::new_read(&src[18..]); |
| 55 | let mut br = ByteReader::new(&mut mr); |
| 56 | let tag = br.read_tag()?; |
| 57 | if &tag == b"iMUS" { |
| 58 | self.tot_size = br.read_u32be()?; |
| 59 | validate!(self.tot_size != 0); |
| 60 | loop { |
| 61 | let tag = br.read_tag()?; |
| 62 | let size = br.read_u32be()?; |
| 63 | match &tag { |
| 64 | b"DATA" => { |
| 65 | break; |
| 66 | }, |
| 67 | _ => br.read_skip(size as usize)?, |
| 68 | }; |
| 69 | } |
| 70 | br.tell() as usize |
| 71 | } else { |
| 72 | self.tot_size = 1; |
| 73 | self.old = true; |
| 74 | self.bits = 8; |
| 75 | 0 |
| 76 | } |
| 77 | } else { 0 }; |
| 78 | |
| 79 | let data = &src[offset + 18..]; |
| 80 | if self.old { |
| 81 | self.queued.extend_from_slice(data); |
| 82 | } |
| 83 | let nsamples = (match self.bits { |
| 84 | _ if self.old => { |
| 85 | let mut mr = MemoryReader::new_read(&self.queued); |
| 86 | let mut br = ByteReader::new(&mut mr); |
| 87 | let mut nblocks = 0; |
| 88 | while br.left() > 0 { |
| 89 | let len = br.read_u16be()? as usize; |
| 90 | if br.left() < (len as i64) { |
| 91 | break; |
| 92 | } |
| 93 | nblocks += 1; |
| 94 | br.read_skip(len)?; |
| 95 | } |
| 96 | nblocks * 1024 * self.chmap.num_channels() |
| 97 | }, |
| 98 | 8 => data.len(), |
| 99 | 12 => data.len() * 2 / 3, |
| 100 | 16 => data.len() / 2, |
| 101 | _ => unimplemented!(), |
| 102 | }) / self.chmap.num_channels(); |
| 103 | |
| 104 | let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?; |
| 105 | let mut adata = abuf.get_abuf_i16().unwrap(); |
| 106 | let adata = adata.get_data_mut().unwrap(); |
| 107 | match self.bits { |
| 108 | _ if self.old => { |
| 109 | let mut mr = MemoryReader::new_read(&self.queued); |
| 110 | let mut br = ByteReader::new(&mut mr); |
| 111 | for dst in adata.chunks_exact_mut(1024 * 2) { |
| 112 | let len = br.read_u16be()? as usize; |
| 113 | let end = br.tell() + (len as u64); |
| 114 | let b = br.read_byte()?; |
| 115 | let scale1 = b >> 4; |
| 116 | let scale2 = b & 0xF; |
| 117 | for pair in dst.chunks_exact_mut(2) { |
| 118 | if br.left() < 2 { |
| 119 | break; |
| 120 | } |
| 121 | let b = br.read_byte()? as i8; |
| 122 | if b != -0x80 { |
| 123 | pair[0] = i16::from(b) << scale1; |
| 124 | } else { |
| 125 | pair[0] = br.read_u16be()? as i16; |
| 126 | } |
| 127 | let b = br.read_byte()? as i8; |
| 128 | if b != -0x80 { |
| 129 | pair[1] = i16::from(b) << scale2; |
| 130 | } else { |
| 131 | pair[1] = br.read_u16be()? as i16; |
| 132 | } |
| 133 | } |
| 134 | validate!(br.tell() <= end); |
| 135 | br.seek(SeekFrom::Start(end))?; |
| 136 | } |
| 137 | let consumed = br.tell() as usize; |
| 138 | self.queued.drain(..consumed); |
| 139 | }, |
| 140 | 8 => { |
| 141 | for (dst, &src) in adata.iter_mut().zip(data.iter()) { |
| 142 | *dst = (u16::from(src) << 8) as i16; |
| 143 | } |
| 144 | }, |
| 145 | 12 => { |
| 146 | for (dst, src) in adata.chunks_exact_mut(2).zip(data.chunks_exact(3)) { |
| 147 | dst[0] = (((u16::from(src[1] << 4) << 8) | (u16::from(src[0]) << 4)) ^ 0x8000) as i16; |
| 148 | dst[1] = (((u16::from(src[1] & 0xF0) << 8) | (u16::from(src[2]) << 4)) ^ 0x8000) as i16; |
| 149 | } |
| 150 | }, |
| 151 | 16 => { |
| 152 | for (dst, src) in adata.iter_mut().zip(data.chunks_exact(2)) { |
| 153 | *dst = read_u16le(src)? as i16; |
| 154 | } |
| 155 | }, |
| 156 | _ => unreachable!(), |
| 157 | } |
| 158 | |
| 159 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); |
| 160 | frm.set_duration(Some(nsamples as u64)); |
| 161 | frm.set_keyframe(true); |
| 162 | Ok(frm.into_ref()) |
| 163 | } else { |
| 164 | Err(DecoderError::InvalidData) |
| 165 | } |
| 166 | } |
| 167 | fn flush(&mut self) { |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | impl NAOptionHandler for IACTDecoder { |
| 172 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } |
| 173 | fn set_options(&mut self, _options: &[NAOption]) { } |
| 174 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } |
| 175 | } |
| 176 | |
| 177 | pub fn get_decoder_iact() -> Box<dyn NADecoder + Send> { |
| 178 | Box::new(IACTDecoder::new()) |
| 179 | } |
| 180 | |
| 181 | #[cfg(test)] |
| 182 | mod test { |
| 183 | use nihav_core::codecs::RegisteredDecoders; |
| 184 | use nihav_core::demuxers::RegisteredDemuxers; |
| 185 | use nihav_codec_support::test::dec_video::*; |
| 186 | use crate::game_register_all_decoders; |
| 187 | use crate::game_register_all_demuxers; |
| 188 | #[test] |
| 189 | fn test_smush_iact_imuse() { |
| 190 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 191 | game_register_all_demuxers(&mut dmx_reg); |
| 192 | let mut dec_reg = RegisteredDecoders::new(); |
| 193 | game_register_all_decoders(&mut dec_reg); |
| 194 | |
| 195 | // sample from The Dig |
| 196 | test_decoding("smush", "smush-iact", "assets/Game/smush/PIGOUT.SAN", None, &dmx_reg, &dec_reg, |
| 197 | ExpectedTestResult::MD5([0x7d731a75, 0x9869cb8f, 0xded5b893, 0xb507b17a])); |
| 198 | } |
| 199 | #[test] |
| 200 | fn test_smush_iact_raw() { |
| 201 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 202 | game_register_all_demuxers(&mut dmx_reg); |
| 203 | let mut dec_reg = RegisteredDecoders::new(); |
| 204 | game_register_all_decoders(&mut dec_reg); |
| 205 | |
| 206 | // sample from Curse of Monkey Island |
| 207 | test_decoding("smush", "smush-iact", "assets/Game/smush/ZAP010.SAN", None, &dmx_reg, &dec_reg, |
| 208 | ExpectedTestResult::MD5([0xecf88bc6, 0x5c89ce94, 0x8e40a22a, 0xfc4ba86c])); |
| 209 | } |
| 210 | } |
| 211 | |