VMD demuxer and decoder
[nihav.git] / nihav-game / src / codecs / vmd.rs
CommitLineData
9895bd7b
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3use std::str::FromStr;
4
5macro_rules! lz_op {
6 (read; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $br:expr, $dst_size:expr) => {
7 validate!($dpos < $dst_size);
8 let b = $br.read_byte()?;
9 $dst[$dpos] = b;
10 $dpos += 1;
11 $window[$wpos] = b;
12 $wpos = ($wpos + 1) & 0xFFF;
13 };
14 (copy; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $off:expr, $dst_size:expr) => {
15 let b = $window[$off];
16 validate!($dpos < $dst_size);
17 $dst[$dpos] = b;
18 $dpos += 1;
19 $window[$wpos] = b;
20 $wpos = ($wpos + 1) & 0xFFF;
21 $off = ($off + 1) & 0xFFF;
22 };
23}
24fn lz_unpack(br: &mut ByteReader, dst: &mut [u8]) -> DecoderResult<()> {
25 let mut window: [u8; 0x1000] = [0x20; 0x1000];
26
27 let dst_size = br.read_u32le()? as usize;
28 validate!(dst_size <= dst.len());
29 let mut pos;
30 let esc_len;
31 if br.peek_u32le()? == 0x56781234 {
32 br.read_skip(4)?;
33 pos = 0x111;
34 esc_len = 15;
35 } else {
36 pos = 0xFEE;
37 esc_len = 255;
38 }
39
40 let mut opos = 0;
41 while br.left() > 0 && opos < dst_size {
42 let op = br.read_byte()?;
43 if (op == 0xFF) && (br.left() > 8) {
44 for _ in 0..8 {
45 lz_op!(read; dst, opos, window, pos, br, dst_size);
46 }
47 } else {
48 for i in 0..8 {
49 if opos == dst_size { break; }
50 let is_literal = ((op >> i) & 1) != 0;
51 if is_literal {
52 lz_op!(read; dst, opos, window, pos, br, dst_size);
53 } else {
54 let b0 = br.read_byte()? as usize;
55 let b1 = br.read_byte()? as usize;
56 let mut off = b0 | ((b1 & 0xF0) << 4);
57 let mut len = b1 & 0xF;
58 if len == esc_len {
59 len = (br.read_byte()? as usize) + esc_len;
60 }
61 for _ in 0..len+3 {
62 lz_op!(copy; dst, opos, window, pos, off, dst_size);
63 }
64 }
65 }
66 }
67 }
68 Ok(())
69}
70
71fn rle_unpack(br: &mut ByteReader, len: usize, dst: &mut [u8]) -> DecoderResult<()> {
72 let end = br.tell() + (len as u64);
73 let mut dpos = 0;
74 if (len & 1) != 0 {
75 dst[dpos] = br.read_byte()?;
76 dpos += 1;
77 }
78 while dpos < dst.len() && br.tell() < end {
79 let val = br.read_byte()?;
80 let len = ((val & 0x7F) as usize) * 2;
81 validate!(dpos + len <= dst.len());
82 if (val & 0x80) != 0 {
83 let dst = &mut dst[dpos..][..len];
84 br.read_buf(dst)?;
85 } else {
86 let val = br.read_byte()?;
87 for i in 0..len {
88 dst[dpos + i] = val;
89 }
90 }
91 dpos += len;
92 }
93 Ok(())
94}
95
96fn decode_frame_data(br: &mut ByteReader, dst: &mut [u8], mut dpos: usize, stride: usize, w: usize, h: usize, method: u8) -> DecoderResult<bool> {
97 match method {
98 1 => {
99 for _ in 0..h {
100 let mut x = 0;
101 while x < w {
102 let val = br.read_byte()?;
103 let len = ((val & 0x7F) as usize) + 1;
104 validate!(x + len <= w);
105 if (val & 0x80) != 0 {
106 let pix = &mut dst[dpos + x..][..len];
107 br.read_buf(pix)?;
108 } // otherwise skip already existing data
109 x += len;
110 }
111 dpos += stride;
112 }
113 Ok(false)
114 },
115 2 => {
116 for _ in 0..h {
117 let pix = &mut dst[dpos..][..w];
118 br.read_buf(pix)?;
119 dpos += stride;
120 }
121 Ok(true)
122 },
123 3 => {
124 for _ in 0..h {
125 let mut x = 0;
126 while x < w {
127 let val = br.read_byte()?;
128 let len = ((val & 0x7F) as usize) + 1;
129 validate!(x + len <= w);
130 if (val & 0x80) != 0 {
131 let pix = &mut dst[dpos + x..][..len];
132 if br.peek_byte()? == 0xFF {
133 br.read_skip(1)?;
134 rle_unpack(br, len, pix)?;
135 } else {
136 br.read_buf(pix)?;
137 }
138 } // otherwise data is already there
139 x += len;
140 }
141 dpos += stride;
142 }
143 Ok(false)
144 },
145 _ => return Err(DecoderError::InvalidData),
146 }
147}
148
149struct VMDVideoDecoder {
150 info: Rc<NACodecInfo>,
151 pal: [u8; 768],
152 buf: Vec<u8>,
153 width: usize,
154 height: usize,
155 hams: HAMShuffler,
156}
157
158impl VMDVideoDecoder {
159 fn new() -> Self {
160 Self {
161 info: Rc::new(NACodecInfo::default()),
162 pal: [0; 768],
163 buf: Vec::new(),
164 width: 0,
165 height: 0,
166 hams: HAMShuffler::default(),
167 }
168 }
169 fn decode_frame(&mut self, br: &mut ByteReader, buf: &mut NAVideoBuffer<u8>) -> DecoderResult<bool> {
170 let paloff = buf.get_offset(1);
171 let stride = buf.get_stride(0);
172 let mut data = buf.get_data_mut();
173 let dst = data.as_mut_slice();
174
175 let frame_x = br.read_u16le()? as usize;
176 let frame_y = br.read_u16le()? as usize;
177 let frame_l = br.read_u16le()? as usize;
178 let frame_d = br.read_u16le()? as usize;
179 br.read_skip(1)?;
180 let flags = br.read_byte()?;
181 let has_pal = (flags & 0x02) != 0;
182 validate!(frame_l >= frame_x && frame_d >= frame_y);
183 validate!(frame_l < self.width && frame_d < self.height);
184
185 if has_pal {
186 br.read_skip(2)?;
187 for e in self.pal.iter_mut() {
188 let val = br.read_byte()?;
189 *e = (val << 2) | (val >> 4);
190 }
191 }
192
193 let dpal = &mut dst[paloff..][..768];
194 dpal.copy_from_slice(&self.pal[0..]);
195
196 if br.left() == 0 { return Ok(false); }
197
198 let w = frame_l + 1 - frame_x;
199 let h = frame_d + 1 - frame_y;
200 let dpos = frame_x + frame_y * stride;
201
202 let method = br.read_byte()?;
203 let is_intra;
204 if (method & 0x80) != 0 {
205 validate!(self.buf.len() > 0);
206 lz_unpack(br, &mut self.buf)?;
207 let mut mr = MemoryReader::new_read(&self.buf);
208 let mut buf_br = ByteReader::new(&mut mr);
209 is_intra = decode_frame_data(&mut buf_br, dst, dpos, stride, w, h, method & 0x7F)?;
210 } else {
211 is_intra = decode_frame_data(br, dst, dpos, stride, w, h, method & 0x7F)?;
212 }
213 Ok(is_intra && frame_x == 0 && frame_y == 0 && w == self.width && h == self.height)
214 }
215}
216
217impl NADecoder for VMDVideoDecoder {
218 fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
219 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
220 self.width = vinfo.get_width();
221 self.height = vinfo.get_height();
222 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, PAL8_FORMAT));
223 self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));
224 validate!(info.get_extradata().is_some());
225
226 if let Some(ref edata) = info.get_extradata() {
227 validate!(edata.len() == 0x330);
228 let unp_size = read_u32le(&edata[800..])? as usize;
229 validate!(unp_size < self.width * self.height * 3 + 64); // just for sanity
230 self.buf.resize(unp_size, 0);
231 for i in 0..768 {
232 let el = edata[28 + i];
233 self.pal[i] = (el << 2) | (el >> 4);
234 }
235 }
236
237 Ok(())
238 } else {
239 Err(DecoderError::InvalidData)
240 }
241 }
242 fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
243 let src = pkt.get_buffer();
244 validate!(src.len() >= 10);
245
246 let mut mr = MemoryReader::new_read(&src);
247 let mut br = ByteReader::new(&mut mr);
248
249 let mut buf;
250 let bufret = self.hams.clone_ref();
251 if let Some(bbuf) = bufret {
252 buf = bbuf;
253 } else {
254 let bufret = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4);
255 if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
256 let bufinfo = bufret.unwrap();
257 buf = bufinfo.get_vbuf().unwrap();
258 self.hams.add_frame(buf);
259 buf = self.hams.get_output_frame().unwrap();
260 }
261
262 let is_intra = self.decode_frame(&mut br, &mut buf)?;
263
264 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
265 frm.set_keyframe(is_intra);
266 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
267 Ok(Rc::new(RefCell::new(frm)))
268 }
269}
270
271
272pub fn get_decoder_video() -> Box<NADecoder> {
273 Box::new(VMDVideoDecoder::new())
274}
275
276struct VMDAudioDecoder {
277 ainfo: NAAudioInfo,
278 chmap: NAChannelMap,
279 is16bit: bool,
280 blk_align: usize,
281 blk_size: usize,
282}
283
284const SOL_AUD_STEPS16: [i16; 128] = [
285 0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
286 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
287 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160,
288 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0,
289 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
290 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270,
291 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0,
292 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0,
293 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330,
294 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
295 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0,
296 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0,
297 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580,
298 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780,
299 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
300 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
301];
302
303impl VMDAudioDecoder {
304 fn new() -> Self {
305 Self {
306 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
307 chmap: NAChannelMap::new(),
308 is16bit: false,
309 blk_align: 0,
310 blk_size: 0,
311 }
312 }
313 fn decode_16bit(&self, dst: &mut [i16], off1: usize, br: &mut ByteReader, nblocks: usize, mut mask: u32) -> DecoderResult<()> {
314 let channels = self.chmap.num_channels();
315 let mut off = [0, off1];
316 for _ in 0..nblocks {
317 if (mask & 1) != 0 {
318 for ch in 0..channels {
319 for i in 0..self.blk_align {
320 dst[off[ch] + i] = 0;
321 }
322 off[ch] += self.blk_align;
323 }
324 } else {
325 let mut pred: [i32; 2] = [0; 2];
326 for ch in 0..channels {
327 pred[ch] = br.read_u16le()? as i32;
328 dst[off[ch]] = pred[ch] as i16;
329 off[ch] += 1;
330 }
331 let mut ch = 0;
332 let flip_ch = if channels == 2 { 1 } else { 0 };
333 for _ in 1..self.blk_align {
334 let b = br.read_byte()? as usize;
335 if (b & 0x80) != 0 {
336 pred[ch] -= SOL_AUD_STEPS16[b & 0x7F] as i32;
337 } else {
338 pred[ch] += SOL_AUD_STEPS16[b & 0x7F] as i32;
339 }
340 //pred[ch] = pred[ch].max(-32768).min(32767);
341 dst[off[ch]] = pred[ch] as i16;
342 off[ch] += 1;
343 ch ^= flip_ch;
344 }
345 }
346 mask >>= 1;
347 }
348 validate!(br.left() == 0);
349 Ok(())
350 }
351}
352
353impl NADecoder for VMDAudioDecoder {
354 fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
355 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
356 let fmt;
357 if ainfo.get_format().get_bits() == 8 {
358 fmt = SND_U8_FORMAT;
359 self.is16bit = false;
360 self.blk_size = ainfo.get_block_len();
361 } else {
362 fmt = SND_S16P_FORMAT;
363 self.is16bit = true;
364 self.blk_size = (ainfo.get_block_len() + 1) * (ainfo.get_channels() as usize);
365 };
366 self.blk_align = ainfo.get_block_len() / (ainfo.get_channels() as usize);
367 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
368 self.chmap = NAChannelMap::from_str(if ainfo.get_channels() == 1 { "C" } else { "L,R" }).unwrap();
369 Ok(())
370 } else {
371 Err(DecoderError::InvalidData)
372 }
373 }
374 fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
375 let info = pkt.get_stream().get_info();
376 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
377 let pktbuf = pkt.get_buffer();
378 validate!(pktbuf.len() >= 6);
379 let mut mr = MemoryReader::new_read(&pktbuf);
380 let mut br = ByteReader::new(&mut mr);
381 let blk_type = br.read_byte()?;
382 br.read_skip(9)?;
383 let mask;
384 let nblocks;
385 if blk_type == 2 { // initial
386 mask = br.read_u32le()?;
387 nblocks = (mask.count_ones() as usize) + (pktbuf.len() - 14) / self.blk_size;
388 } else if blk_type == 3 { // silence
389 mask = 1;
390 nblocks = 1;
391 } else {
392 mask = 0;
393 nblocks = 1;
394 }
395 let samples = nblocks * self.blk_align;
396 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
397 if self.is16bit {
398 let mut adata = abuf.get_abuf_i16().unwrap();
399 let off1 = adata.get_offset(1);
400 let mut dst = adata.get_data_mut();
401 self.decode_16bit(&mut dst, off1, &mut br, nblocks, mask)?;
402 } else {
403 let mut adata = abuf.get_abuf_u8().unwrap();
404 let mut dst = adata.get_data_mut();
405 let mut doff = 0;
406 let mut mask = mask;
407 let channels = self.chmap.num_channels();
408 for _ in 0..nblocks {
409 if (mask & 1) != 0 {
410 for i in 0..self.blk_align * channels {
411 dst[doff + i] = 0;
412 }
413 } else {
414 for i in 0..self.blk_align * channels {
415 dst[doff + i] = br.read_byte()?;
416 }
417 }
418 doff += self.blk_align;
419 mask >>= 1;
420 }
421 }
422
423 let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
424 frm.set_duration(Some(samples as u64));
425 frm.set_keyframe(true);
426 Ok(Rc::new(RefCell::new(frm)))
427 } else {
428 Err(DecoderError::InvalidData)
429 }
430 }
431}
432
433pub fn get_decoder_audio() -> Box<NADecoder> {
434 Box::new(VMDAudioDecoder::new())
435}
436
437#[cfg(test)]
438mod test {
439 use nihav_core::codecs::RegisteredDecoders;
440 use nihav_core::demuxers::RegisteredDemuxers;
441 use nihav_core::test::dec_video::*;
442 use crate::codecs::game_register_all_codecs;
443 use crate::demuxers::game_register_all_demuxers;
444 #[test]
445 fn test_vmd_video() {
446 let mut dmx_reg = RegisteredDemuxers::new();
447 game_register_all_demuxers(&mut dmx_reg);
448 let mut dec_reg = RegisteredDecoders::new();
449 game_register_all_codecs(&mut dec_reg);
450
451// let file = "assets/1491.VMD";
452 let file = "assets/128.vmd";
453 test_file_decoding("vmd", file, Some(10), true, false, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
454 }
455 #[test]
456 fn test_vmd_audio() {
457 let mut dmx_reg = RegisteredDemuxers::new();
458 game_register_all_demuxers(&mut dmx_reg);
459 let mut dec_reg = RegisteredDecoders::new();
460 game_register_all_codecs(&mut dec_reg);
461
462// let file = "assets/1491.VMD";
463 let file = "assets/128.vmd";
464 test_decode_audio("vmd", file, None, "vmd", &dmx_reg, &dec_reg);
465 }
466}