]> git.nihav.org Git - nihav.git/blame - nihav-game/src/codecs/vmd.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-game / src / codecs / vmd.rs
CommitLineData
9895bd7b
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
979faef7 3use nihav_codec_support::codecs::imaadpcm::*;
9895bd7b 4use std::str::FromStr;
f45dfcf7 5use std::sync::Arc;
9895bd7b
KS
6
7macro_rules! lz_op {
8 (read; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $br:expr, $dst_size:expr) => {
9 validate!($dpos < $dst_size);
10 let b = $br.read_byte()?;
11 $dst[$dpos] = b;
12 $dpos += 1;
13 $window[$wpos] = b;
14 $wpos = ($wpos + 1) & 0xFFF;
15 };
16 (copy; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $off:expr, $dst_size:expr) => {
17 let b = $window[$off];
18 validate!($dpos < $dst_size);
19 $dst[$dpos] = b;
20 $dpos += 1;
21 $window[$wpos] = b;
22 $wpos = ($wpos + 1) & 0xFFF;
23 $off = ($off + 1) & 0xFFF;
24 };
25}
26fn lz_unpack(br: &mut ByteReader, dst: &mut [u8]) -> DecoderResult<()> {
27 let mut window: [u8; 0x1000] = [0x20; 0x1000];
28
29 let dst_size = br.read_u32le()? as usize;
30 validate!(dst_size <= dst.len());
31 let mut pos;
32 let esc_len;
33 if br.peek_u32le()? == 0x56781234 {
34 br.read_skip(4)?;
35 pos = 0x111;
36 esc_len = 15;
37 } else {
38 pos = 0xFEE;
39 esc_len = 255;
40 }
41
42 let mut opos = 0;
43 while br.left() > 0 && opos < dst_size {
44 let op = br.read_byte()?;
45 if (op == 0xFF) && (br.left() > 8) {
46 for _ in 0..8 {
47 lz_op!(read; dst, opos, window, pos, br, dst_size);
48 }
49 } else {
50 for i in 0..8 {
51 if opos == dst_size { break; }
52 let is_literal = ((op >> i) & 1) != 0;
53 if is_literal {
54 lz_op!(read; dst, opos, window, pos, br, dst_size);
55 } else {
56 let b0 = br.read_byte()? as usize;
57 let b1 = br.read_byte()? as usize;
58 let mut off = b0 | ((b1 & 0xF0) << 4);
59 let mut len = b1 & 0xF;
60 if len == esc_len {
61 len = (br.read_byte()? as usize) + esc_len;
62 }
63 for _ in 0..len+3 {
64 lz_op!(copy; dst, opos, window, pos, off, dst_size);
65 }
66 }
67 }
68 }
69 }
70 Ok(())
71}
72
73fn rle_unpack(br: &mut ByteReader, len: usize, dst: &mut [u8]) -> DecoderResult<()> {
74 let end = br.tell() + (len as u64);
75 let mut dpos = 0;
76 if (len & 1) != 0 {
77 dst[dpos] = br.read_byte()?;
78 dpos += 1;
79 }
80 while dpos < dst.len() && br.tell() < end {
81 let val = br.read_byte()?;
82 let len = ((val & 0x7F) as usize) * 2;
83 validate!(dpos + len <= dst.len());
84 if (val & 0x80) != 0 {
85 let dst = &mut dst[dpos..][..len];
86 br.read_buf(dst)?;
87 } else {
771e522a
KS
88 let val1 = br.read_byte()?;
89 let val2 = br.read_byte()?;
90 for i in (0..len).step_by(2) {
91 dst[dpos + i] = val1;
92 dst[dpos + i + 1] = val2;
9895bd7b
KS
93 }
94 }
95 dpos += len;
96 }
97 Ok(())
98}
99
100fn decode_frame_data(br: &mut ByteReader, dst: &mut [u8], mut dpos: usize, stride: usize, w: usize, h: usize, method: u8) -> DecoderResult<bool> {
101 match method {
102 1 => {
103 for _ in 0..h {
104 let mut x = 0;
105 while x < w {
106 let val = br.read_byte()?;
107 let len = ((val & 0x7F) as usize) + 1;
108 validate!(x + len <= w);
109 if (val & 0x80) != 0 {
110 let pix = &mut dst[dpos + x..][..len];
111 br.read_buf(pix)?;
112 } // otherwise skip already existing data
113 x += len;
114 }
115 dpos += stride;
116 }
117 Ok(false)
118 },
119 2 => {
120 for _ in 0..h {
121 let pix = &mut dst[dpos..][..w];
122 br.read_buf(pix)?;
123 dpos += stride;
124 }
125 Ok(true)
126 },
127 3 => {
128 for _ in 0..h {
129 let mut x = 0;
130 while x < w {
131 let val = br.read_byte()?;
132 let len = ((val & 0x7F) as usize) + 1;
133 validate!(x + len <= w);
134 if (val & 0x80) != 0 {
135 let pix = &mut dst[dpos + x..][..len];
136 if br.peek_byte()? == 0xFF {
137 br.read_skip(1)?;
138 rle_unpack(br, len, pix)?;
139 } else {
140 br.read_buf(pix)?;
141 }
142 } // otherwise data is already there
143 x += len;
144 }
145 dpos += stride;
146 }
147 Ok(false)
148 },
e69b1148 149 _ => Err(DecoderError::InvalidData),
9895bd7b
KS
150 }
151}
152
153struct VMDVideoDecoder {
2422d969 154 info: NACodecInfoRef,
9895bd7b
KS
155 pal: [u8; 768],
156 buf: Vec<u8>,
a5e655a7 157 framebuf: Vec<u8>,
9895bd7b
KS
158 width: usize,
159 height: usize,
73a1eecd
KS
160 xoff: usize,
161 yoff: usize,
a5e655a7
KS
162 is_16bit: bool,
163 is_24bit: bool,
164 ver1: u8,
165 ver2: u8,
9895bd7b
KS
166}
167
168impl VMDVideoDecoder {
169 fn new() -> Self {
170 Self {
2422d969 171 info: NACodecInfoRef::default(),
9895bd7b
KS
172 pal: [0; 768],
173 buf: Vec::new(),
a5e655a7 174 framebuf: Vec::new(),
9895bd7b
KS
175 width: 0,
176 height: 0,
73a1eecd
KS
177 xoff: 0,
178 yoff: 0,
a5e655a7
KS
179 is_16bit: false,
180 is_24bit: false,
181 ver1: 0,
182 ver2: 0,
9895bd7b
KS
183 }
184 }
a5e655a7 185 fn decode_frame(&mut self, br: &mut ByteReader) -> DecoderResult<bool> {
9895bd7b
KS
186 let frame_x = br.read_u16le()? as usize;
187 let frame_y = br.read_u16le()? as usize;
02c01d44 188 let frame_r = br.read_u16le()? as usize;
9895bd7b
KS
189 let frame_d = br.read_u16le()? as usize;
190 br.read_skip(1)?;
191 let flags = br.read_byte()?;
a5e655a7 192 let has_pal = (flags & 0x02) != 0 && !self.is_16bit && !self.is_24bit;
02c01d44 193 if (frame_x == 0xFFFF) && (frame_y == 0xFFFF) && (frame_r == 0xFFFF) && (frame_d == 0xFFFF) {
5961ae1d
KS
194 return Ok(false);
195 }
73a1eecd 196 validate!(frame_x >= self.xoff && frame_y >= self.yoff);
02c01d44
KS
197 validate!(frame_r >= frame_x && frame_d >= frame_y);
198 validate!(frame_r - self.xoff < self.width && frame_d - self.yoff < self.height);
9895bd7b
KS
199
200 if has_pal {
201 br.read_skip(2)?;
202 for e in self.pal.iter_mut() {
203 let val = br.read_byte()?;
204 *e = (val << 2) | (val >> 4);
205 }
206 }
207
9895bd7b
KS
208 if br.left() == 0 { return Ok(false); }
209
a5e655a7
KS
210 let bpp = if (!self.is_16bit && !self.is_24bit) || self.ver1 < 2 {
211 1
212 } else if self.is_16bit {
213 2
214 } else {
215 3
216 };
02c01d44 217 let w = (frame_r + 1 - frame_x) * bpp;
9895bd7b 218 let h = frame_d + 1 - frame_y;
a5e655a7
KS
219 let stride = self.width;
220 let dpos = (frame_x - self.xoff) * bpp + (frame_y - self.yoff) * stride;
9895bd7b
KS
221
222 let method = br.read_byte()?;
cb56d166
KS
223 let is_intra = if (method & 0x80) != 0 {
224 validate!(!self.buf.is_empty());
225 lz_unpack(br, &mut self.buf)?;
226 let mut mr = MemoryReader::new_read(&self.buf);
227 let mut buf_br = ByteReader::new(&mut mr);
228 decode_frame_data(&mut buf_br, &mut self.framebuf, dpos, stride, w, h, method & 0x7F)?
229 } else {
230 decode_frame_data(br, &mut self.framebuf, dpos, stride, w, h, method & 0x7F)?
231 };
9895bd7b
KS
232 Ok(is_intra && frame_x == 0 && frame_y == 0 && w == self.width && h == self.height)
233 }
234}
235
a5e655a7
KS
236const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
237 comp_info: [
238 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
239 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 1, next_elem: 2 }),
240 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 2, next_elem: 2 }),
241 None, None],
242 elem_size: 2, be: false, alpha: false, palette: false };
243
9895bd7b 244impl NADecoder for VMDVideoDecoder {
01613464 245 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
246 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
247 self.width = vinfo.get_width();
248 self.height = vinfo.get_height();
9895bd7b
KS
249 validate!(info.get_extradata().is_some());
250
251 if let Some(ref edata) = info.get_extradata() {
252 validate!(edata.len() == 0x330);
253 let unp_size = read_u32le(&edata[800..])? as usize;
ed6c9f8a 254 validate!(unp_size < self.width * self.height * 4 + 64); // just for sanity
9895bd7b
KS
255 self.buf.resize(unp_size, 0);
256 for i in 0..768 {
257 let el = edata[28 + i];
258 self.pal[i] = (el << 2) | (el >> 4);
259 }
73a1eecd
KS
260 self.xoff = read_u16le(&edata[8..])? as usize;
261 self.yoff = read_u16le(&edata[10..])? as usize;
a5e655a7
KS
262 self.ver1 = edata[2];
263 self.ver2 = edata[4];
264 } else {
265 unreachable!();
9895bd7b 266 }
a5e655a7
KS
267 let (disp_width, fmt) = if self.ver2 < 5 {
268 (self.width, PAL8_FORMAT)
269 } else if self.ver2 < 13 {
270 self.is_24bit = true;
271 if self.ver1 >= 2 {
272 self.width *= 3;
273 }
274 validate!(self.width % 3 == 0);
275 (self.width / 3, RGB24_FORMAT)
276 } else {
277 self.is_16bit = true;
278 if self.ver1 >= 2 {
279 self.width *= 2;
280 }
281 (self.width / 2, RGB555_FORMAT)
282 };
283 self.framebuf = vec!(0; self.width * self.height);
284
285 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(disp_width, self.height, false, fmt));
286 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
9895bd7b
KS
287
288 Ok(())
289 } else {
290 Err(DecoderError::InvalidData)
291 }
292 }
01613464 293 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
294 let src = pkt.get_buffer();
295 validate!(src.len() >= 10);
296
297 let mut mr = MemoryReader::new_read(&src);
298 let mut br = ByteReader::new(&mut mr);
299
a5e655a7
KS
300 let is_intra = self.decode_frame(&mut br)?;
301
302 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
303 let videobuf;
304 if !self.is_16bit {
305 let mut buf = bufinfo.get_vbuf().unwrap();
306 let stride = buf.get_stride(0);
307 let paloff = buf.get_offset(1);
308 let data = buf.get_data_mut().unwrap();
309 for (inrow, outrow) in self.framebuf.chunks(self.width).zip(data.chunks_mut(stride)) {
e6aaad5c 310 outrow[..self.width].copy_from_slice(inrow);
a5e655a7
KS
311 }
312 if !self.is_24bit {
e6aaad5c 313 data[paloff..][..768].copy_from_slice(&self.pal);
a5e655a7
KS
314 }
315 videobuf = if !self.is_24bit { NABufferType::Video(buf) } else { NABufferType::VideoPacked(buf) };
9895bd7b 316 } else {
a5e655a7
KS
317 let mut buf = bufinfo.get_vbuf16().unwrap();
318 let stride = buf.get_stride(0);
319 let data = buf.get_data_mut().unwrap();
320 for (inrow, outrow) in self.framebuf.chunks(self.width).zip(data.chunks_mut(stride)) {
321 for i in (0..self.width).step_by(2) {
322 outrow[i >> 1] = read_u16le(&inrow[i..])?;
323 }
324 }
325 videobuf = NABufferType::Video16(buf);
9895bd7b
KS
326 }
327
a5e655a7 328 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), videobuf);
9895bd7b
KS
329 frm.set_keyframe(is_intra);
330 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
171860fc 331 Ok(frm.into_ref())
9895bd7b 332 }
f9be4e75 333 fn flush(&mut self) {
f9be4e75 334 }
9895bd7b
KS
335}
336
7d57ae2f
KS
337impl NAOptionHandler for VMDVideoDecoder {
338 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
339 fn set_options(&mut self, _options: &[NAOption]) { }
340 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
341}
342
9895bd7b 343
08a1fab7 344pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
345 Box::new(VMDVideoDecoder::new())
346}
347
f45dfcf7
KS
348#[derive(Clone,Copy,PartialEq)]
349enum VMDAudioMode {
350 U8,
351 DPCM,
352 StereoDPCM,
979faef7 353 ADPCM,
f45dfcf7
KS
354}
355
9895bd7b
KS
356struct VMDAudioDecoder {
357 ainfo: NAAudioInfo,
f45dfcf7 358 info: Arc<NACodecInfo>,
9895bd7b 359 chmap: NAChannelMap,
9895bd7b
KS
360 blk_align: usize,
361 blk_size: usize,
f45dfcf7
KS
362 mode: VMDAudioMode,
363 pred: [i32; 2],
364 last_byte: Option<u8>,
365 is_odd: bool,
366 ch: usize,
9895bd7b
KS
367}
368
369const SOL_AUD_STEPS16: [i16; 128] = [
370 0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
371 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
372 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160,
373 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0,
374 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
375 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270,
376 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0,
377 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0,
378 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330,
379 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
380 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0,
381 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0,
382 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580,
383 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780,
384 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
385 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
386];
387
388impl VMDAudioDecoder {
389 fn new() -> Self {
390 Self {
391 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
f45dfcf7 392 info: NACodecInfo::new_dummy(),
9895bd7b 393 chmap: NAChannelMap::new(),
9895bd7b
KS
394 blk_align: 0,
395 blk_size: 0,
f45dfcf7
KS
396 mode: VMDAudioMode::U8,
397 pred: [0; 2],
398 last_byte: None,
399 is_odd: false,
400 ch: 0,
9895bd7b
KS
401 }
402 }
403 fn decode_16bit(&self, dst: &mut [i16], off1: usize, br: &mut ByteReader, nblocks: usize, mut mask: u32) -> DecoderResult<()> {
404 let channels = self.chmap.num_channels();
405 let mut off = [0, off1];
406 for _ in 0..nblocks {
407 if (mask & 1) != 0 {
408 for ch in 0..channels {
409 for i in 0..self.blk_align {
410 dst[off[ch] + i] = 0;
411 }
412 off[ch] += self.blk_align;
413 }
414 } else {
415 let mut pred: [i32; 2] = [0; 2];
416 for ch in 0..channels {
e69b1148 417 pred[ch] = i32::from(br.read_u16le()?);
9895bd7b
KS
418 dst[off[ch]] = pred[ch] as i16;
419 off[ch] += 1;
420 }
421 let mut ch = 0;
422 let flip_ch = if channels == 2 { 1 } else { 0 };
aa7e65d2 423 for _ in channels..self.blk_align*channels {
f45dfcf7 424 pred[ch] = Self::pred16(pred[ch], br.read_byte()?);
9895bd7b
KS
425 //pred[ch] = pred[ch].max(-32768).min(32767);
426 dst[off[ch]] = pred[ch] as i16;
427 off[ch] += 1;
428 ch ^= flip_ch;
429 }
430 }
431 mask >>= 1;
432 }
433 validate!(br.left() == 0);
434 Ok(())
435 }
f45dfcf7
KS
436 fn pred16(pred: i32, val: u8) -> i32 {
437 if (val & 0x80) != 0 {
438 pred - i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
439 } else {
440 pred + i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
441 }
442 }
9895bd7b
KS
443}
444
445impl NADecoder for VMDAudioDecoder {
01613464 446 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
447 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
448 let fmt;
f45dfcf7
KS
449 let channels = ainfo.get_channels() as usize;
450 let edata = info.get_extradata();
451 let flags = if let Some(ref buf) = edata {
452 validate!(buf.len() >= 2);
7450554d 453 u16::from(buf[0]) | (u16::from(buf[1]) << 8)
f45dfcf7
KS
454 } else {
455 0
456 };
457 validate!((channels == 1) ^ ((flags & 0x8200) != 0));
9895bd7b 458 if ainfo.get_format().get_bits() == 8 {
9895bd7b 459 self.blk_size = ainfo.get_block_len();
f45dfcf7
KS
460 self.blk_align = ainfo.get_block_len() / channels;
461 if (flags & 0x8000) == 0 {
462 fmt = SND_U8_FORMAT;
463 self.mode = VMDAudioMode::U8;
464 } else {
465 fmt = SND_S16_FORMAT;
466 self.mode = VMDAudioMode::StereoDPCM;
467 self.is_odd = (channels == 2) && ((self.blk_size & 1) != 0);
468 }
9895bd7b 469 } else {
aa7e65d2 470 self.blk_align = ainfo.get_block_len();
979faef7 471 if (flags & 0x10) == 0 {
5be37b03 472 fmt = SND_S16P_FORMAT;
979faef7
KS
473 self.blk_size = (ainfo.get_block_len() + 1) * channels;
474 self.mode = VMDAudioMode::DPCM;
475 } else {
5be37b03
KS
476 fmt = SND_S16_FORMAT;
477 self.blk_size = (ainfo.get_block_len() * channels + 1) / 2 + 3 * channels;
979faef7
KS
478 self.mode = VMDAudioMode::ADPCM;
479 }
9895bd7b 480 };
9895bd7b 481 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
7450554d 482 self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo));
f45dfcf7 483 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
9895bd7b
KS
484 Ok(())
485 } else {
486 Err(DecoderError::InvalidData)
487 }
488 }
7450554d 489 #[allow(clippy::identity_op)]
b7c882c1 490 #[allow(clippy::cognitive_complexity)]
01613464 491 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
492 let info = pkt.get_stream().get_info();
493 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
494 let pktbuf = pkt.get_buffer();
495 validate!(pktbuf.len() >= 6);
496 let mut mr = MemoryReader::new_read(&pktbuf);
497 let mut br = ByteReader::new(&mut mr);
498 let blk_type = br.read_byte()?;
499 br.read_skip(9)?;
500 let mask;
501 let nblocks;
502 if blk_type == 2 { // initial
503 mask = br.read_u32le()?;
504 nblocks = (mask.count_ones() as usize) + (pktbuf.len() - 14) / self.blk_size;
505 } else if blk_type == 3 { // silence
506 mask = 1;
507 nblocks = 1;
508 } else {
509 mask = 0;
510 nblocks = 1;
511 }
f45dfcf7
KS
512 let mut samples = nblocks * self.blk_align;
513 if self.mode == VMDAudioMode::StereoDPCM && self.is_odd {
514 samples += (nblocks + if self.last_byte.is_some() { 1 } else { 0 }) / 2;
515 }
9895bd7b 516 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
f45dfcf7
KS
517 match self.mode {
518 VMDAudioMode::DPCM => {
519 let mut adata = abuf.get_abuf_i16().unwrap();
520 let off1 = adata.get_offset(1);
6f263099
KS
521 let dst = adata.get_data_mut().unwrap();
522 self.decode_16bit(dst, off1, &mut br, nblocks, mask)?;
f45dfcf7
KS
523 },
524 VMDAudioMode::U8 => {
525 let mut adata = abuf.get_abuf_u8().unwrap();
526 let dst = adata.get_data_mut().unwrap();
527 let mut doff = 0;
528 let mut mask = mask;
529 let channels = self.chmap.num_channels();
530 for _ in 0..nblocks {
531 if (mask & 1) != 0 {
532 for i in 0..self.blk_align * channels {
533 dst[doff + i] = 128;
534 }
535 } else if channels == 1 {
536 for i in 0..self.blk_size {
537 dst[doff + i] = br.read_byte()?;
538 }
539 } else {
e63a7720 540 unreachable!();
9895bd7b 541 }
f45dfcf7
KS
542 doff += self.blk_align * channels;
543 mask >>= 1;
544 }
545 },
546 VMDAudioMode::StereoDPCM => {
547 let mut adata = abuf.get_abuf_i16().unwrap();
548 let dst = adata.get_data_mut().unwrap();
549 let mut doff = 0;
550 let mut mask = mask;
551 let mut ch = self.ch;
552 for _ in 0..nblocks {
553 let put_sample = self.last_byte.is_some();
554 if let (true, Some(val)) = (self.is_odd, self.last_byte) {
555 self.pred[ch] = Self::pred16(self.pred[ch], val);
556 dst[doff] = self.pred[ch] as i16;
557 doff += 1;
558 ch ^= 1;
559 self.last_byte = None;
9895bd7b 560 }
f45dfcf7
KS
561 if (mask & 1) != 0 {
562 for i in 0..self.blk_align {
563 dst[doff + i * 2 + 0] = self.pred[ch] as i16;
564 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
565 }
566 if self.is_odd {
567 if put_sample {
568 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
569 doff += 1;
570 ch ^= 1;
571 } else {
572 self.last_byte = Some(0);
573 }
574 }
575 } else {
576 for i in 0..self.blk_align {
577 self.pred[ch] = Self::pred16(self.pred[ch], br.read_byte()?);
578 dst[doff + i * 2] = self.pred[ch] as i16;
579 self.pred[ch ^ 1] = Self::pred16(self.pred[ch ^ 1], br.read_byte()?);
580 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
581 }
582 if self.is_odd {
583 let val = br.read_byte()?;
584 if put_sample {
585 self.pred[ch] = Self::pred16(self.pred[ch], val);
586 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
587 doff += 1;
588 ch ^= 1;
589 } else {
590 self.last_byte = Some(val);
591 }
aa7e65d2
KS
592 }
593 }
f45dfcf7
KS
594 doff += self.blk_align * 2;
595 mask >>= 1;
9895bd7b 596 }
f45dfcf7
KS
597 self.ch = ch;
598 },
979faef7
KS
599 VMDAudioMode::ADPCM => {
600 let mut adata = abuf.get_abuf_i16().unwrap();
601 let dst = adata.get_data_mut().unwrap();
602 let mut doff = 0;
603 if self.chmap.num_channels() == 1 {
604 let mut mask = mask;
605 let mut ima = IMAState::new();
606 for _ in 0..nblocks {
607 if (mask & 1) != 0 {
5be37b03
KS
608 for i in 0..self.blk_align {
609 dst[doff + i] = 0;
610 }
3e91c67b 611 doff += self.blk_align;
979faef7
KS
612 mask >>= 1;
613 continue;
614 }
615 let pred = br.read_u16le()? as i16;
616 let step = br.read_byte()?;
617 validate!((step as usize) < IMA_STEP_TABLE.len());
618 ima.reset(pred, step);
3e91c67b
KS
619 let mut b = 0;
620 for i in 0..self.blk_align {
621 if (i & 1) == 0 {
622 b = br.read_byte()?;
623 dst[doff] = ima.expand_sample(b >> 4);
624 } else {
625 dst[doff] = ima.expand_sample(b & 0xF);
626 }
979faef7
KS
627 doff += 1;
628 }
629 mask >>= 1;
630 }
631 } else {
5be37b03
KS
632 let mut mask = mask;
633 let mut ima1 = IMAState::new();
634 let mut ima2 = IMAState::new();
635 for _ in 0..nblocks {
636 if (mask & 1) != 0 {
637 for i in 0..self.blk_align * 2 {
638 dst[doff + i] = 0;
639 }
640 doff += self.blk_align * 2;
641 mask >>= 1;
642 continue;
643 }
644 let pred1 = br.read_u16le()? as i16;
645 let pred2 = br.read_u16le()? as i16;
646 let step1 = br.read_byte()?;
647 let step2 = br.read_byte()?;
648 validate!((step1 as usize) < IMA_STEP_TABLE.len());
649 validate!((step2 as usize) < IMA_STEP_TABLE.len());
650 ima1.reset(pred1, step1);
651 ima2.reset(pred2, step2);
652 for _ in 0..self.blk_align {
653 let b = br.read_byte()?;
654 dst[doff] = ima1.expand_sample(b >> 4);
655 doff += 1;
656 dst[doff] = ima2.expand_sample(b & 0xF);
657 doff += 1;
658 }
659 mask >>= 1;
660 }
979faef7
KS
661 }
662 },
f45dfcf7 663 };
9895bd7b 664
f45dfcf7 665 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
9895bd7b
KS
666 frm.set_duration(Some(samples as u64));
667 frm.set_keyframe(true);
171860fc 668 Ok(frm.into_ref())
9895bd7b
KS
669 } else {
670 Err(DecoderError::InvalidData)
671 }
672 }
f9be4e75
KS
673 fn flush(&mut self) {
674 }
9895bd7b
KS
675}
676
7d57ae2f
KS
677impl NAOptionHandler for VMDAudioDecoder {
678 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
679 fn set_options(&mut self, _options: &[NAOption]) { }
680 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
681}
682
08a1fab7 683pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
684 Box::new(VMDAudioDecoder::new())
685}
686
687#[cfg(test)]
688mod test {
689 use nihav_core::codecs::RegisteredDecoders;
690 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 691 use nihav_codec_support::test::dec_video::*;
78fb6560 692 use crate::game_register_all_decoders;
e64739f8 693 use crate::game_register_all_demuxers;
886cde48 694 // samples from https://samples.mplayerhq.hu/game-formats/sierra-vmd/ and various games
9895bd7b
KS
695 #[test]
696 fn test_vmd_video() {
697 let mut dmx_reg = RegisteredDemuxers::new();
698 game_register_all_demuxers(&mut dmx_reg);
699 let mut dec_reg = RegisteredDecoders::new();
78fb6560 700 game_register_all_decoders(&mut dec_reg);
9895bd7b 701
3900194b 702 test_decoding("vmd", "vmd-video", "assets/Game/sierra/2832.VMD", Some(10), &dmx_reg, &dec_reg,
fe435580
KS
703 ExpectedTestResult::MD5Frames(vec![
704 [0xd29e0214, 0xf38ad154, 0xccbd381f, 0x3de1109c],
705 [0x904074eb, 0x202b1d6f, 0xe3f68538, 0xf0db641c],
706 [0x9c8b1b6c, 0xe205b8dc, 0xbfb07406, 0x993ace41],
707 [0x71ce4220, 0x8747fd05, 0x854dd86d, 0x2664cde5],
708 [0x3bc65fa4, 0xebb95292, 0xe0a0fea6, 0x0acfdea1],
709 [0x33982045, 0x8d11b69b, 0xac254a75, 0x63896a21],
710 [0xa667db33, 0x90e122d3, 0x2243da15, 0xcc4bffd2],
711 [0x518621c1, 0xb91412bc, 0x12312869, 0x141ef647],
712 [0x3069977e, 0x68fd3fa0, 0x2bfdb00d, 0x1e694684],
713 [0x246c12aa, 0x15137fb0, 0xa4b0fc3e, 0x626a2676],
714 [0x72cce7e3, 0x98506d04, 0xd4d8bbaf, 0x3cc5e32d]]));
9895bd7b
KS
715 }
716 #[test]
40e5d0b8
KS
717 fn test_vmd_video_16bpp() {
718 let mut dmx_reg = RegisteredDemuxers::new();
719 game_register_all_demuxers(&mut dmx_reg);
720 let mut dec_reg = RegisteredDecoders::new();
78fb6560 721 game_register_all_decoders(&mut dec_reg);
40e5d0b8 722
3900194b 723 test_decoding("vmd", "vmd-video", "assets/Game/sierra/HLP1000.VMD", Some(10), &dmx_reg, &dec_reg,
40e5d0b8
KS
724 ExpectedTestResult::MD5Frames(vec![
725 [0x03d77d51, 0x8670ae24, 0x86184cc8, 0x9c928700],
726 [0xf4796f1b, 0x0f75a120, 0x62056509, 0xc83f1a2c],
727 [0xd9e6db4d, 0x7af82082, 0xac6a335c, 0x19b8438f],
728 [0x03d77d51, 0x8670ae24, 0x86184cc8, 0x9c928700],
729 [0xd9e6db4d, 0x7af82082, 0xac6a335c, 0x19b8438f],
730 [0xf4796f1b, 0x0f75a120, 0x62056509, 0xc83f1a2c]]));
731 }
732 #[test]
733 fn test_vmd_video_24bpp() {
734 let mut dmx_reg = RegisteredDemuxers::new();
735 game_register_all_demuxers(&mut dmx_reg);
736 let mut dec_reg = RegisteredDecoders::new();
78fb6560 737 game_register_all_decoders(&mut dec_reg);
40e5d0b8 738
3900194b 739 test_decoding("vmd", "vmd-video", "assets/Game/sierra/02C.VMD", None, &dmx_reg, &dec_reg,
40e5d0b8
KS
740 ExpectedTestResult::MD5([0xb580782c, 0xd7fb98c0, 0xaf9b83cc, 0xaea0846b]));
741 }
742 #[test]
fe435580 743 fn test_vmd_audio_u8() {
9895bd7b
KS
744 let mut dmx_reg = RegisteredDemuxers::new();
745 game_register_all_demuxers(&mut dmx_reg);
746 let mut dec_reg = RegisteredDecoders::new();
78fb6560 747 game_register_all_decoders(&mut dec_reg);
9895bd7b 748
3900194b 749 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/1491.VMD", None, &dmx_reg, &dec_reg,
fe435580
KS
750 ExpectedTestResult::MD5([0x75037601, 0xbc7b3976, 0x6e1c948b, 0xf05a3d6c]));
751 }
752 #[test]
753 fn test_vmd_audio_s16_old() {
754 let mut dmx_reg = RegisteredDemuxers::new();
755 game_register_all_demuxers(&mut dmx_reg);
756 let mut dec_reg = RegisteredDecoders::new();
78fb6560 757 game_register_all_decoders(&mut dec_reg);
fe435580 758
3900194b 759 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/2832.VMD", None, &dmx_reg, &dec_reg,
fe435580
KS
760 ExpectedTestResult::MD5([0x32dcdf0e, 0xee058684, 0x43ed5bf1, 0x2ff18b5a]));
761 }
762 #[test]
763 fn test_vmd_audio_s16_new() {
764 let mut dmx_reg = RegisteredDemuxers::new();
765 game_register_all_demuxers(&mut dmx_reg);
766 let mut dec_reg = RegisteredDecoders::new();
78fb6560 767 game_register_all_decoders(&mut dec_reg);
fe435580 768
3900194b 769 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/1000.VMD", None, &dmx_reg, &dec_reg,
fe435580 770 ExpectedTestResult::MD5([0xc36215d3, 0x96530a80, 0x89f1fa8e, 0x49da302b]));
9895bd7b 771 }
40e5d0b8
KS
772 #[test]
773 fn test_vmd_audio_ima_adpcm() {
774 let mut dmx_reg = RegisteredDemuxers::new();
775 game_register_all_demuxers(&mut dmx_reg);
776 let mut dec_reg = RegisteredDecoders::new();
78fb6560 777 game_register_all_decoders(&mut dec_reg);
40e5d0b8 778
3900194b 779 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/HLP1000.VMD", None, &dmx_reg, &dec_reg,
40e5d0b8
KS
780 ExpectedTestResult::MD5([0x76a00405, 0xe4e5378d, 0x495b2a68, 0x4dffe042]));
781 }
9895bd7b 782}