]> git.nihav.org Git - nihav.git/blame - nihav-game/src/codecs/vmd.rs
mov: support segmented files
[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()?;
223 let is_intra;
224 if (method & 0x80) != 0 {
e69b1148 225 validate!(!self.buf.is_empty());
9895bd7b
KS
226 lz_unpack(br, &mut self.buf)?;
227 let mut mr = MemoryReader::new_read(&self.buf);
228 let mut buf_br = ByteReader::new(&mut mr);
a5e655a7 229 is_intra = decode_frame_data(&mut buf_br, &mut self.framebuf, dpos, stride, w, h, method & 0x7F)?;
9895bd7b 230 } else {
a5e655a7 231 is_intra = decode_frame_data(br, &mut self.framebuf, dpos, stride, w, h, method & 0x7F)?;
9895bd7b
KS
232 }
233 Ok(is_intra && frame_x == 0 && frame_y == 0 && w == self.width && h == self.height)
234 }
235}
236
a5e655a7
KS
237const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
238 comp_info: [
239 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
240 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 1, next_elem: 2 }),
241 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 2, next_elem: 2 }),
242 None, None],
243 elem_size: 2, be: false, alpha: false, palette: false };
244
9895bd7b 245impl NADecoder for VMDVideoDecoder {
01613464 246 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
247 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
248 self.width = vinfo.get_width();
249 self.height = vinfo.get_height();
9895bd7b
KS
250 validate!(info.get_extradata().is_some());
251
252 if let Some(ref edata) = info.get_extradata() {
253 validate!(edata.len() == 0x330);
254 let unp_size = read_u32le(&edata[800..])? as usize;
ed6c9f8a 255 validate!(unp_size < self.width * self.height * 4 + 64); // just for sanity
9895bd7b
KS
256 self.buf.resize(unp_size, 0);
257 for i in 0..768 {
258 let el = edata[28 + i];
259 self.pal[i] = (el << 2) | (el >> 4);
260 }
73a1eecd
KS
261 self.xoff = read_u16le(&edata[8..])? as usize;
262 self.yoff = read_u16le(&edata[10..])? as usize;
a5e655a7
KS
263 self.ver1 = edata[2];
264 self.ver2 = edata[4];
265 } else {
266 unreachable!();
9895bd7b 267 }
a5e655a7
KS
268 let (disp_width, fmt) = if self.ver2 < 5 {
269 (self.width, PAL8_FORMAT)
270 } else if self.ver2 < 13 {
271 self.is_24bit = true;
272 if self.ver1 >= 2 {
273 self.width *= 3;
274 }
275 validate!(self.width % 3 == 0);
276 (self.width / 3, RGB24_FORMAT)
277 } else {
278 self.is_16bit = true;
279 if self.ver1 >= 2 {
280 self.width *= 2;
281 }
282 (self.width / 2, RGB555_FORMAT)
283 };
284 self.framebuf = vec!(0; self.width * self.height);
285
286 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(disp_width, self.height, false, fmt));
287 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
9895bd7b
KS
288
289 Ok(())
290 } else {
291 Err(DecoderError::InvalidData)
292 }
293 }
01613464 294 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
295 let src = pkt.get_buffer();
296 validate!(src.len() >= 10);
297
298 let mut mr = MemoryReader::new_read(&src);
299 let mut br = ByteReader::new(&mut mr);
300
a5e655a7
KS
301 let is_intra = self.decode_frame(&mut br)?;
302
303 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
304 let videobuf;
305 if !self.is_16bit {
306 let mut buf = bufinfo.get_vbuf().unwrap();
307 let stride = buf.get_stride(0);
308 let paloff = buf.get_offset(1);
309 let data = buf.get_data_mut().unwrap();
310 for (inrow, outrow) in self.framebuf.chunks(self.width).zip(data.chunks_mut(stride)) {
311 (&mut outrow[..self.width]).copy_from_slice(inrow);
312 }
313 if !self.is_24bit {
314 (&mut data[paloff..][..768]).copy_from_slice(&self.pal);
315 }
316 videobuf = if !self.is_24bit { NABufferType::Video(buf) } else { NABufferType::VideoPacked(buf) };
9895bd7b 317 } else {
a5e655a7
KS
318 let mut buf = bufinfo.get_vbuf16().unwrap();
319 let stride = buf.get_stride(0);
320 let data = buf.get_data_mut().unwrap();
321 for (inrow, outrow) in self.framebuf.chunks(self.width).zip(data.chunks_mut(stride)) {
322 for i in (0..self.width).step_by(2) {
323 outrow[i >> 1] = read_u16le(&inrow[i..])?;
324 }
325 }
326 videobuf = NABufferType::Video16(buf);
9895bd7b
KS
327 }
328
a5e655a7 329 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), videobuf);
9895bd7b
KS
330 frm.set_keyframe(is_intra);
331 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
171860fc 332 Ok(frm.into_ref())
9895bd7b 333 }
f9be4e75 334 fn flush(&mut self) {
f9be4e75 335 }
9895bd7b
KS
336}
337
7d57ae2f
KS
338impl NAOptionHandler for VMDVideoDecoder {
339 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
340 fn set_options(&mut self, _options: &[NAOption]) { }
341 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
342}
343
9895bd7b 344
08a1fab7 345pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
346 Box::new(VMDVideoDecoder::new())
347}
348
f45dfcf7
KS
349#[derive(Clone,Copy,PartialEq)]
350enum VMDAudioMode {
351 U8,
352 DPCM,
353 StereoDPCM,
979faef7 354 ADPCM,
f45dfcf7
KS
355}
356
9895bd7b
KS
357struct VMDAudioDecoder {
358 ainfo: NAAudioInfo,
f45dfcf7 359 info: Arc<NACodecInfo>,
9895bd7b 360 chmap: NAChannelMap,
9895bd7b
KS
361 blk_align: usize,
362 blk_size: usize,
f45dfcf7
KS
363 mode: VMDAudioMode,
364 pred: [i32; 2],
365 last_byte: Option<u8>,
366 is_odd: bool,
367 ch: usize,
9895bd7b
KS
368}
369
370const SOL_AUD_STEPS16: [i16; 128] = [
371 0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
372 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
373 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160,
374 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0,
375 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
376 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270,
377 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0,
378 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0,
379 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330,
380 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
381 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0,
382 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0,
383 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580,
384 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780,
385 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
386 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
387];
388
389impl VMDAudioDecoder {
390 fn new() -> Self {
391 Self {
392 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
f45dfcf7 393 info: NACodecInfo::new_dummy(),
9895bd7b 394 chmap: NAChannelMap::new(),
9895bd7b
KS
395 blk_align: 0,
396 blk_size: 0,
f45dfcf7
KS
397 mode: VMDAudioMode::U8,
398 pred: [0; 2],
399 last_byte: None,
400 is_odd: false,
401 ch: 0,
9895bd7b
KS
402 }
403 }
404 fn decode_16bit(&self, dst: &mut [i16], off1: usize, br: &mut ByteReader, nblocks: usize, mut mask: u32) -> DecoderResult<()> {
405 let channels = self.chmap.num_channels();
406 let mut off = [0, off1];
407 for _ in 0..nblocks {
408 if (mask & 1) != 0 {
409 for ch in 0..channels {
410 for i in 0..self.blk_align {
411 dst[off[ch] + i] = 0;
412 }
413 off[ch] += self.blk_align;
414 }
415 } else {
416 let mut pred: [i32; 2] = [0; 2];
417 for ch in 0..channels {
e69b1148 418 pred[ch] = i32::from(br.read_u16le()?);
9895bd7b
KS
419 dst[off[ch]] = pred[ch] as i16;
420 off[ch] += 1;
421 }
422 let mut ch = 0;
423 let flip_ch = if channels == 2 { 1 } else { 0 };
aa7e65d2 424 for _ in channels..self.blk_align*channels {
f45dfcf7 425 pred[ch] = Self::pred16(pred[ch], br.read_byte()?);
9895bd7b
KS
426 //pred[ch] = pred[ch].max(-32768).min(32767);
427 dst[off[ch]] = pred[ch] as i16;
428 off[ch] += 1;
429 ch ^= flip_ch;
430 }
431 }
432 mask >>= 1;
433 }
434 validate!(br.left() == 0);
435 Ok(())
436 }
f45dfcf7
KS
437 fn pred16(pred: i32, val: u8) -> i32 {
438 if (val & 0x80) != 0 {
439 pred - i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
440 } else {
441 pred + i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
442 }
443 }
9895bd7b
KS
444}
445
446impl NADecoder for VMDAudioDecoder {
01613464 447 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
448 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
449 let fmt;
f45dfcf7
KS
450 let channels = ainfo.get_channels() as usize;
451 let edata = info.get_extradata();
452 let flags = if let Some(ref buf) = edata {
453 validate!(buf.len() >= 2);
7450554d 454 u16::from(buf[0]) | (u16::from(buf[1]) << 8)
f45dfcf7
KS
455 } else {
456 0
457 };
458 validate!((channels == 1) ^ ((flags & 0x8200) != 0));
9895bd7b 459 if ainfo.get_format().get_bits() == 8 {
9895bd7b 460 self.blk_size = ainfo.get_block_len();
f45dfcf7
KS
461 self.blk_align = ainfo.get_block_len() / channels;
462 if (flags & 0x8000) == 0 {
463 fmt = SND_U8_FORMAT;
464 self.mode = VMDAudioMode::U8;
465 } else {
466 fmt = SND_S16_FORMAT;
467 self.mode = VMDAudioMode::StereoDPCM;
468 self.is_odd = (channels == 2) && ((self.blk_size & 1) != 0);
469 }
9895bd7b 470 } else {
aa7e65d2 471 self.blk_align = ainfo.get_block_len();
979faef7 472 if (flags & 0x10) == 0 {
5be37b03 473 fmt = SND_S16P_FORMAT;
979faef7
KS
474 self.blk_size = (ainfo.get_block_len() + 1) * channels;
475 self.mode = VMDAudioMode::DPCM;
476 } else {
5be37b03
KS
477 fmt = SND_S16_FORMAT;
478 self.blk_size = (ainfo.get_block_len() * channels + 1) / 2 + 3 * channels;
979faef7
KS
479 self.mode = VMDAudioMode::ADPCM;
480 }
9895bd7b 481 };
9895bd7b 482 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
7450554d 483 self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo));
f45dfcf7 484 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
9895bd7b
KS
485 Ok(())
486 } else {
487 Err(DecoderError::InvalidData)
488 }
489 }
7450554d
KS
490 #[allow(clippy::identity_op)]
491 #[allow(clippy::cyclomatic_complexity)]
01613464 492 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
493 let info = pkt.get_stream().get_info();
494 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
495 let pktbuf = pkt.get_buffer();
496 validate!(pktbuf.len() >= 6);
497 let mut mr = MemoryReader::new_read(&pktbuf);
498 let mut br = ByteReader::new(&mut mr);
499 let blk_type = br.read_byte()?;
500 br.read_skip(9)?;
501 let mask;
502 let nblocks;
503 if blk_type == 2 { // initial
504 mask = br.read_u32le()?;
505 nblocks = (mask.count_ones() as usize) + (pktbuf.len() - 14) / self.blk_size;
506 } else if blk_type == 3 { // silence
507 mask = 1;
508 nblocks = 1;
509 } else {
510 mask = 0;
511 nblocks = 1;
512 }
f45dfcf7
KS
513 let mut samples = nblocks * self.blk_align;
514 if self.mode == VMDAudioMode::StereoDPCM && self.is_odd {
515 samples += (nblocks + if self.last_byte.is_some() { 1 } else { 0 }) / 2;
516 }
9895bd7b 517 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
f45dfcf7
KS
518 match self.mode {
519 VMDAudioMode::DPCM => {
520 let mut adata = abuf.get_abuf_i16().unwrap();
521 let off1 = adata.get_offset(1);
522 let mut dst = adata.get_data_mut().unwrap();
523 self.decode_16bit(&mut dst, off1, &mut br, nblocks, mask)?;
524 },
525 VMDAudioMode::U8 => {
526 let mut adata = abuf.get_abuf_u8().unwrap();
527 let dst = adata.get_data_mut().unwrap();
528 let mut doff = 0;
529 let mut mask = mask;
530 let channels = self.chmap.num_channels();
531 for _ in 0..nblocks {
532 if (mask & 1) != 0 {
533 for i in 0..self.blk_align * channels {
534 dst[doff + i] = 128;
535 }
536 } else if channels == 1 {
537 for i in 0..self.blk_size {
538 dst[doff + i] = br.read_byte()?;
539 }
540 } else {
e63a7720 541 unreachable!();
9895bd7b 542 }
f45dfcf7
KS
543 doff += self.blk_align * channels;
544 mask >>= 1;
545 }
546 },
547 VMDAudioMode::StereoDPCM => {
548 let mut adata = abuf.get_abuf_i16().unwrap();
549 let dst = adata.get_data_mut().unwrap();
550 let mut doff = 0;
551 let mut mask = mask;
552 let mut ch = self.ch;
553 for _ in 0..nblocks {
554 let put_sample = self.last_byte.is_some();
555 if let (true, Some(val)) = (self.is_odd, self.last_byte) {
556 self.pred[ch] = Self::pred16(self.pred[ch], val);
557 dst[doff] = self.pred[ch] as i16;
558 doff += 1;
559 ch ^= 1;
560 self.last_byte = None;
9895bd7b 561 }
f45dfcf7
KS
562 if (mask & 1) != 0 {
563 for i in 0..self.blk_align {
564 dst[doff + i * 2 + 0] = self.pred[ch] as i16;
565 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
566 }
567 if self.is_odd {
568 if put_sample {
569 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
570 doff += 1;
571 ch ^= 1;
572 } else {
573 self.last_byte = Some(0);
574 }
575 }
576 } else {
577 for i in 0..self.blk_align {
578 self.pred[ch] = Self::pred16(self.pred[ch], br.read_byte()?);
579 dst[doff + i * 2] = self.pred[ch] as i16;
580 self.pred[ch ^ 1] = Self::pred16(self.pred[ch ^ 1], br.read_byte()?);
581 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
582 }
583 if self.is_odd {
584 let val = br.read_byte()?;
585 if put_sample {
586 self.pred[ch] = Self::pred16(self.pred[ch], val);
587 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
588 doff += 1;
589 ch ^= 1;
590 } else {
591 self.last_byte = Some(val);
592 }
aa7e65d2
KS
593 }
594 }
f45dfcf7
KS
595 doff += self.blk_align * 2;
596 mask >>= 1;
9895bd7b 597 }
f45dfcf7
KS
598 self.ch = ch;
599 },
979faef7
KS
600 VMDAudioMode::ADPCM => {
601 let mut adata = abuf.get_abuf_i16().unwrap();
602 let dst = adata.get_data_mut().unwrap();
603 let mut doff = 0;
604 if self.chmap.num_channels() == 1 {
605 let mut mask = mask;
606 let mut ima = IMAState::new();
607 for _ in 0..nblocks {
608 if (mask & 1) != 0 {
5be37b03
KS
609 for i in 0..self.blk_align {
610 dst[doff + i] = 0;
611 }
3e91c67b 612 doff += self.blk_align;
979faef7
KS
613 mask >>= 1;
614 continue;
615 }
616 let pred = br.read_u16le()? as i16;
617 let step = br.read_byte()?;
618 validate!((step as usize) < IMA_STEP_TABLE.len());
619 ima.reset(pred, step);
3e91c67b
KS
620 let mut b = 0;
621 for i in 0..self.blk_align {
622 if (i & 1) == 0 {
623 b = br.read_byte()?;
624 dst[doff] = ima.expand_sample(b >> 4);
625 } else {
626 dst[doff] = ima.expand_sample(b & 0xF);
627 }
979faef7
KS
628 doff += 1;
629 }
630 mask >>= 1;
631 }
632 } else {
5be37b03
KS
633 let mut mask = mask;
634 let mut ima1 = IMAState::new();
635 let mut ima2 = IMAState::new();
636 for _ in 0..nblocks {
637 if (mask & 1) != 0 {
638 for i in 0..self.blk_align * 2 {
639 dst[doff + i] = 0;
640 }
641 doff += self.blk_align * 2;
642 mask >>= 1;
643 continue;
644 }
645 let pred1 = br.read_u16le()? as i16;
646 let pred2 = br.read_u16le()? as i16;
647 let step1 = br.read_byte()?;
648 let step2 = br.read_byte()?;
649 validate!((step1 as usize) < IMA_STEP_TABLE.len());
650 validate!((step2 as usize) < IMA_STEP_TABLE.len());
651 ima1.reset(pred1, step1);
652 ima2.reset(pred2, step2);
653 for _ in 0..self.blk_align {
654 let b = br.read_byte()?;
655 dst[doff] = ima1.expand_sample(b >> 4);
656 doff += 1;
657 dst[doff] = ima2.expand_sample(b & 0xF);
658 doff += 1;
659 }
660 mask >>= 1;
661 }
979faef7
KS
662 }
663 },
f45dfcf7 664 };
9895bd7b 665
f45dfcf7 666 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
9895bd7b
KS
667 frm.set_duration(Some(samples as u64));
668 frm.set_keyframe(true);
171860fc 669 Ok(frm.into_ref())
9895bd7b
KS
670 } else {
671 Err(DecoderError::InvalidData)
672 }
673 }
f9be4e75
KS
674 fn flush(&mut self) {
675 }
9895bd7b
KS
676}
677
7d57ae2f
KS
678impl NAOptionHandler for VMDAudioDecoder {
679 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
680 fn set_options(&mut self, _options: &[NAOption]) { }
681 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
682}
683
08a1fab7 684pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
685 Box::new(VMDAudioDecoder::new())
686}
687
688#[cfg(test)]
689mod test {
690 use nihav_core::codecs::RegisteredDecoders;
691 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 692 use nihav_codec_support::test::dec_video::*;
78fb6560 693 use crate::game_register_all_decoders;
e64739f8 694 use crate::game_register_all_demuxers;
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
fe435580
KS
702 test_decoding("vmd", "vmd-video", "assets/Game/2832.VMD", Some(10), &dmx_reg, &dec_reg,
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
KS
722
723 test_decoding("vmd", "vmd-video", "assets/Game/HLP1000.VMD", Some(10), &dmx_reg, &dec_reg,
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
KS
738
739 test_decoding("vmd", "vmd-video", "assets/Game/02C.VMD", None, &dmx_reg, &dec_reg,
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
fe435580
KS
749 test_decoding("vmd", "vmd-audio", "assets/Game/1491.VMD", None, &dmx_reg, &dec_reg,
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
KS
758
759 test_decoding("vmd", "vmd-audio", "assets/Game/2832.VMD", None, &dmx_reg, &dec_reg,
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
KS
768
769 test_decoding("vmd", "vmd-audio", "assets/Game/1000.VMD", None, &dmx_reg, &dec_reg,
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
KS
778
779 test_decoding("vmd", "vmd-audio", "assets/Game/HLP1000.VMD", None, &dmx_reg, &dec_reg,
780 ExpectedTestResult::MD5([0x76a00405, 0xe4e5378d, 0x495b2a68, 0x4dffe042]));
781 }
9895bd7b 782}