]> git.nihav.org Git - nihav.git/blame_incremental - 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
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3use nihav_codec_support::codecs::imaadpcm::*;
4use std::str::FromStr;
5use std::sync::Arc;
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 {
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;
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 },
149 _ => Err(DecoderError::InvalidData),
150 }
151}
152
153struct VMDVideoDecoder {
154 info: NACodecInfoRef,
155 pal: [u8; 768],
156 buf: Vec<u8>,
157 framebuf: Vec<u8>,
158 width: usize,
159 height: usize,
160 xoff: usize,
161 yoff: usize,
162 is_16bit: bool,
163 is_24bit: bool,
164 ver1: u8,
165 ver2: u8,
166}
167
168impl VMDVideoDecoder {
169 fn new() -> Self {
170 Self {
171 info: NACodecInfoRef::default(),
172 pal: [0; 768],
173 buf: Vec::new(),
174 framebuf: Vec::new(),
175 width: 0,
176 height: 0,
177 xoff: 0,
178 yoff: 0,
179 is_16bit: false,
180 is_24bit: false,
181 ver1: 0,
182 ver2: 0,
183 }
184 }
185 fn decode_frame(&mut self, br: &mut ByteReader) -> DecoderResult<bool> {
186 let frame_x = br.read_u16le()? as usize;
187 let frame_y = br.read_u16le()? as usize;
188 let frame_r = br.read_u16le()? as usize;
189 let frame_d = br.read_u16le()? as usize;
190 br.read_skip(1)?;
191 let flags = br.read_byte()?;
192 let has_pal = (flags & 0x02) != 0 && !self.is_16bit && !self.is_24bit;
193 if (frame_x == 0xFFFF) && (frame_y == 0xFFFF) && (frame_r == 0xFFFF) && (frame_d == 0xFFFF) {
194 return Ok(false);
195 }
196 validate!(frame_x >= self.xoff && frame_y >= self.yoff);
197 validate!(frame_r >= frame_x && frame_d >= frame_y);
198 validate!(frame_r - self.xoff < self.width && frame_d - self.yoff < self.height);
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
208 if br.left() == 0 { return Ok(false); }
209
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 };
217 let w = (frame_r + 1 - frame_x) * bpp;
218 let h = frame_d + 1 - frame_y;
219 let stride = self.width;
220 let dpos = (frame_x - self.xoff) * bpp + (frame_y - self.yoff) * stride;
221
222 let method = br.read_byte()?;
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 };
232 Ok(is_intra && frame_x == 0 && frame_y == 0 && w == self.width && h == self.height)
233 }
234}
235
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
244impl NADecoder for VMDVideoDecoder {
245 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
246 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
247 self.width = vinfo.get_width();
248 self.height = vinfo.get_height();
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;
254 validate!(unp_size < self.width * self.height * 4 + 64); // just for sanity
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 }
260 self.xoff = read_u16le(&edata[8..])? as usize;
261 self.yoff = read_u16le(&edata[10..])? as usize;
262 self.ver1 = edata[2];
263 self.ver2 = edata[4];
264 } else {
265 unreachable!();
266 }
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();
287
288 Ok(())
289 } else {
290 Err(DecoderError::InvalidData)
291 }
292 }
293 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
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
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)) {
310 outrow[..self.width].copy_from_slice(inrow);
311 }
312 if !self.is_24bit {
313 data[paloff..][..768].copy_from_slice(&self.pal);
314 }
315 videobuf = if !self.is_24bit { NABufferType::Video(buf) } else { NABufferType::VideoPacked(buf) };
316 } else {
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);
326 }
327
328 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), videobuf);
329 frm.set_keyframe(is_intra);
330 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
331 Ok(frm.into_ref())
332 }
333 fn flush(&mut self) {
334 }
335}
336
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
343
344pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
345 Box::new(VMDVideoDecoder::new())
346}
347
348#[derive(Clone,Copy,PartialEq)]
349enum VMDAudioMode {
350 U8,
351 DPCM,
352 StereoDPCM,
353 ADPCM,
354}
355
356struct VMDAudioDecoder {
357 ainfo: NAAudioInfo,
358 info: Arc<NACodecInfo>,
359 chmap: NAChannelMap,
360 blk_align: usize,
361 blk_size: usize,
362 mode: VMDAudioMode,
363 pred: [i32; 2],
364 last_byte: Option<u8>,
365 is_odd: bool,
366 ch: usize,
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),
392 info: NACodecInfo::new_dummy(),
393 chmap: NAChannelMap::new(),
394 blk_align: 0,
395 blk_size: 0,
396 mode: VMDAudioMode::U8,
397 pred: [0; 2],
398 last_byte: None,
399 is_odd: false,
400 ch: 0,
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 {
417 pred[ch] = i32::from(br.read_u16le()?);
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 };
423 for _ in channels..self.blk_align*channels {
424 pred[ch] = Self::pred16(pred[ch], br.read_byte()?);
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 }
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 }
443}
444
445impl NADecoder for VMDAudioDecoder {
446 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
447 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
448 let fmt;
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);
453 u16::from(buf[0]) | (u16::from(buf[1]) << 8)
454 } else {
455 0
456 };
457 validate!((channels == 1) ^ ((flags & 0x8200) != 0));
458 if ainfo.get_format().get_bits() == 8 {
459 self.blk_size = ainfo.get_block_len();
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 }
469 } else {
470 self.blk_align = ainfo.get_block_len();
471 if (flags & 0x10) == 0 {
472 fmt = SND_S16P_FORMAT;
473 self.blk_size = (ainfo.get_block_len() + 1) * channels;
474 self.mode = VMDAudioMode::DPCM;
475 } else {
476 fmt = SND_S16_FORMAT;
477 self.blk_size = (ainfo.get_block_len() * channels + 1) / 2 + 3 * channels;
478 self.mode = VMDAudioMode::ADPCM;
479 }
480 };
481 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
482 self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo));
483 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
484 Ok(())
485 } else {
486 Err(DecoderError::InvalidData)
487 }
488 }
489 #[allow(clippy::identity_op)]
490 #[allow(clippy::cognitive_complexity)]
491 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
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 }
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 }
516 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
517 match self.mode {
518 VMDAudioMode::DPCM => {
519 let mut adata = abuf.get_abuf_i16().unwrap();
520 let off1 = adata.get_offset(1);
521 let dst = adata.get_data_mut().unwrap();
522 self.decode_16bit(dst, off1, &mut br, nblocks, mask)?;
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 {
540 unreachable!();
541 }
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;
560 }
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 }
592 }
593 }
594 doff += self.blk_align * 2;
595 mask >>= 1;
596 }
597 self.ch = ch;
598 },
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 {
608 for i in 0..self.blk_align {
609 dst[doff + i] = 0;
610 }
611 doff += self.blk_align;
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);
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 }
627 doff += 1;
628 }
629 mask >>= 1;
630 }
631 } else {
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 }
661 }
662 },
663 };
664
665 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
666 frm.set_duration(Some(samples as u64));
667 frm.set_keyframe(true);
668 Ok(frm.into_ref())
669 } else {
670 Err(DecoderError::InvalidData)
671 }
672 }
673 fn flush(&mut self) {
674 }
675}
676
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
683pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
684 Box::new(VMDAudioDecoder::new())
685}
686
687#[cfg(test)]
688mod test {
689 use nihav_core::codecs::RegisteredDecoders;
690 use nihav_core::demuxers::RegisteredDemuxers;
691 use nihav_codec_support::test::dec_video::*;
692 use crate::game_register_all_decoders;
693 use crate::game_register_all_demuxers;
694 // samples from https://samples.mplayerhq.hu/game-formats/sierra-vmd/ and various games
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();
700 game_register_all_decoders(&mut dec_reg);
701
702 test_decoding("vmd", "vmd-video", "assets/Game/sierra/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]]));
715 }
716 #[test]
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();
721 game_register_all_decoders(&mut dec_reg);
722
723 test_decoding("vmd", "vmd-video", "assets/Game/sierra/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();
737 game_register_all_decoders(&mut dec_reg);
738
739 test_decoding("vmd", "vmd-video", "assets/Game/sierra/02C.VMD", None, &dmx_reg, &dec_reg,
740 ExpectedTestResult::MD5([0xb580782c, 0xd7fb98c0, 0xaf9b83cc, 0xaea0846b]));
741 }
742 #[test]
743 fn test_vmd_audio_u8() {
744 let mut dmx_reg = RegisteredDemuxers::new();
745 game_register_all_demuxers(&mut dmx_reg);
746 let mut dec_reg = RegisteredDecoders::new();
747 game_register_all_decoders(&mut dec_reg);
748
749 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/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();
757 game_register_all_decoders(&mut dec_reg);
758
759 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/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();
767 game_register_all_decoders(&mut dec_reg);
768
769 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/1000.VMD", None, &dmx_reg, &dec_reg,
770 ExpectedTestResult::MD5([0xc36215d3, 0x96530a80, 0x89f1fa8e, 0x49da302b]));
771 }
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();
777 game_register_all_decoders(&mut dec_reg);
778
779 test_decoding("vmd", "vmd-audio", "assets/Game/sierra/HLP1000.VMD", None, &dmx_reg, &dec_reg,
780 ExpectedTestResult::MD5([0x76a00405, 0xe4e5378d, 0x495b2a68, 0x4dffe042]));
781 }
782}