]> git.nihav.org Git - nihav.git/blob - nihav-game/src/codecs/vmd.rs
codecs: implement Default trait for MV
[nihav.git] / nihav-game / src / codecs / vmd.rs
1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use std::str::FromStr;
4
5 macro_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 }
24 fn 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
71 fn 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
96 fn 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
149 struct VMDVideoDecoder {
150 info: NACodecInfoRef,
151 pal: [u8; 768],
152 buf: Vec<u8>,
153 width: usize,
154 height: usize,
155 hams: HAMShuffler,
156 }
157
158 impl VMDVideoDecoder {
159 fn new() -> Self {
160 Self {
161 info: NACodecInfoRef::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 data = buf.get_data_mut().unwrap();
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
217 impl NADecoder for VMDVideoDecoder {
218 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> 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 = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
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, _supp: &mut NADecoderSupport, 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(frm.into_ref())
268 }
269 }
270
271
272 pub fn get_decoder_video() -> Box<NADecoder> {
273 Box::new(VMDVideoDecoder::new())
274 }
275
276 struct VMDAudioDecoder {
277 ainfo: NAAudioInfo,
278 chmap: NAChannelMap,
279 is16bit: bool,
280 blk_align: usize,
281 blk_size: usize,
282 }
283
284 const 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
303 impl 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 channels..self.blk_align*channels {
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
353 impl NADecoder for VMDAudioDecoder {
354 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> 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 self.blk_align = ainfo.get_block_len() / (ainfo.get_channels() as usize);
362 } else {
363 fmt = SND_S16P_FORMAT;
364 self.is16bit = true;
365 self.blk_size = (ainfo.get_block_len() + 1) * (ainfo.get_channels() as usize);
366 self.blk_align = ainfo.get_block_len();
367 };
368 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
369 self.chmap = NAChannelMap::from_str(if ainfo.get_channels() == 1 { "C" } else { "L,R" }).unwrap();
370 Ok(())
371 } else {
372 Err(DecoderError::InvalidData)
373 }
374 }
375 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
376 let info = pkt.get_stream().get_info();
377 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
378 let pktbuf = pkt.get_buffer();
379 validate!(pktbuf.len() >= 6);
380 let mut mr = MemoryReader::new_read(&pktbuf);
381 let mut br = ByteReader::new(&mut mr);
382 let blk_type = br.read_byte()?;
383 br.read_skip(9)?;
384 let mask;
385 let nblocks;
386 if blk_type == 2 { // initial
387 mask = br.read_u32le()?;
388 nblocks = (mask.count_ones() as usize) + (pktbuf.len() - 14) / self.blk_size;
389 } else if blk_type == 3 { // silence
390 mask = 1;
391 nblocks = 1;
392 } else {
393 mask = 0;
394 nblocks = 1;
395 }
396 let samples = nblocks * self.blk_align;
397 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
398 if self.is16bit {
399 let mut adata = abuf.get_abuf_i16().unwrap();
400 let off1 = adata.get_offset(1);
401 let mut dst = adata.get_data_mut().unwrap();
402 self.decode_16bit(&mut dst, off1, &mut br, nblocks, mask)?;
403 } else {
404 let mut adata = abuf.get_abuf_u8().unwrap();
405 let dst = adata.get_data_mut().unwrap();
406 let mut doff = 0;
407 let mut mask = mask;
408 let channels = self.chmap.num_channels();
409 for _ in 0..nblocks {
410 if (mask & 1) != 0 {
411 for i in 0..self.blk_align * channels {
412 dst[doff + i] = 0;
413 }
414 } else if channels == 1 {
415 for i in 0..self.blk_size {
416 dst[doff + i] = br.read_byte()?;
417 }
418 } else {
419 for i in 0..self.blk_size {
420 let val = br.read_byte()?;
421 if val < 128 {
422 dst[doff + i] = 127 - val;
423 } else {
424 dst[doff + i] = val;
425 }
426 }
427 }
428 doff += self.blk_align * channels;
429 mask >>= 1;
430 }
431 }
432
433 let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
434 frm.set_duration(Some(samples as u64));
435 frm.set_keyframe(true);
436 Ok(frm.into_ref())
437 } else {
438 Err(DecoderError::InvalidData)
439 }
440 }
441 }
442
443 pub fn get_decoder_audio() -> Box<NADecoder> {
444 Box::new(VMDAudioDecoder::new())
445 }
446
447 #[cfg(test)]
448 mod test {
449 use nihav_core::codecs::RegisteredDecoders;
450 use nihav_core::demuxers::RegisteredDemuxers;
451 use nihav_core::test::dec_video::*;
452 use crate::codecs::game_register_all_codecs;
453 use crate::demuxers::game_register_all_demuxers;
454 #[test]
455 fn test_vmd_video() {
456 let mut dmx_reg = RegisteredDemuxers::new();
457 game_register_all_demuxers(&mut dmx_reg);
458 let mut dec_reg = RegisteredDecoders::new();
459 game_register_all_codecs(&mut dec_reg);
460
461 // let file = "assets/Game/1491.VMD";
462 let file = "assets/Game/128.vmd";
463 test_file_decoding("vmd", file, Some(10), true, false, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
464 }
465 #[test]
466 fn test_vmd_audio() {
467 let mut dmx_reg = RegisteredDemuxers::new();
468 game_register_all_demuxers(&mut dmx_reg);
469 let mut dec_reg = RegisteredDecoders::new();
470 game_register_all_codecs(&mut dec_reg);
471
472 // let file = "assets/Game/1491.VMD";
473 let file = "assets/Game/128.vmd";
474 // let file = "assets/Game/1000.VMD";
475 // let file = "assets/Game/235.VMD";
476 test_decode_audio("vmd", file, None, "vmd", &dmx_reg, &dec_reg);
477 }
478 }