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