vmd: ignore empty frames
[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 if (frame_x == 0xFFFF) && (frame_y == 0xFFFF) && (frame_l == 0xFFFF) && (frame_d == 0xFFFF) {
184 return Ok(false);
185 }
186 validate!(frame_l >= frame_x && frame_d >= frame_y);
187 validate!(frame_l < self.width && frame_d < self.height);
188
189 if has_pal {
190 br.read_skip(2)?;
191 for e in self.pal.iter_mut() {
192 let val = br.read_byte()?;
193 *e = (val << 2) | (val >> 4);
194 }
195 }
196
197 let dpal = &mut dst[paloff..][..768];
198 dpal.copy_from_slice(&self.pal[0..]);
199
200 if br.left() == 0 { return Ok(false); }
201
202 let w = frame_l + 1 - frame_x;
203 let h = frame_d + 1 - frame_y;
204 let dpos = frame_x + frame_y * stride;
205
206 let method = br.read_byte()?;
207 let is_intra;
208 if (method & 0x80) != 0 {
209 validate!(!self.buf.is_empty());
210 lz_unpack(br, &mut self.buf)?;
211 let mut mr = MemoryReader::new_read(&self.buf);
212 let mut buf_br = ByteReader::new(&mut mr);
213 is_intra = decode_frame_data(&mut buf_br, dst, dpos, stride, w, h, method & 0x7F)?;
214 } else {
215 is_intra = decode_frame_data(br, dst, dpos, stride, w, h, method & 0x7F)?;
216 }
217 Ok(is_intra && frame_x == 0 && frame_y == 0 && w == self.width && h == self.height)
218 }
219 }
220
221 impl NADecoder for VMDVideoDecoder {
222 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
223 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
224 self.width = vinfo.get_width();
225 self.height = vinfo.get_height();
226 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, PAL8_FORMAT));
227 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
228 validate!(info.get_extradata().is_some());
229
230 if let Some(ref edata) = info.get_extradata() {
231 validate!(edata.len() == 0x330);
232 let unp_size = read_u32le(&edata[800..])? as usize;
233 validate!(unp_size < self.width * self.height * 3 + 64); // just for sanity
234 self.buf.resize(unp_size, 0);
235 for i in 0..768 {
236 let el = edata[28 + i];
237 self.pal[i] = (el << 2) | (el >> 4);
238 }
239 }
240
241 Ok(())
242 } else {
243 Err(DecoderError::InvalidData)
244 }
245 }
246 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
247 let src = pkt.get_buffer();
248 validate!(src.len() >= 10);
249
250 let mut mr = MemoryReader::new_read(&src);
251 let mut br = ByteReader::new(&mut mr);
252
253 let mut buf;
254 let bufret = self.hams.clone_ref();
255 if let Some(bbuf) = bufret {
256 buf = bbuf;
257 } else {
258 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
259 buf = bufinfo.get_vbuf().unwrap();
260 self.hams.add_frame(buf);
261 buf = self.hams.get_output_frame().unwrap();
262 }
263
264 let is_intra = self.decode_frame(&mut br, &mut buf)?;
265
266 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
267 frm.set_keyframe(is_intra);
268 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
269 Ok(frm.into_ref())
270 }
271 fn flush(&mut self) {
272 self.hams.clear();
273 }
274 }
275
276
277 pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
278 Box::new(VMDVideoDecoder::new())
279 }
280
281 struct VMDAudioDecoder {
282 ainfo: NAAudioInfo,
283 chmap: NAChannelMap,
284 is16bit: bool,
285 blk_align: usize,
286 blk_size: usize,
287 }
288
289 const SOL_AUD_STEPS16: [i16; 128] = [
290 0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
291 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
292 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160,
293 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0,
294 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
295 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270,
296 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0,
297 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0,
298 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330,
299 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
300 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0,
301 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0,
302 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580,
303 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780,
304 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
305 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
306 ];
307
308 impl VMDAudioDecoder {
309 fn new() -> Self {
310 Self {
311 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
312 chmap: NAChannelMap::new(),
313 is16bit: false,
314 blk_align: 0,
315 blk_size: 0,
316 }
317 }
318 fn decode_16bit(&self, dst: &mut [i16], off1: usize, br: &mut ByteReader, nblocks: usize, mut mask: u32) -> DecoderResult<()> {
319 let channels = self.chmap.num_channels();
320 let mut off = [0, off1];
321 for _ in 0..nblocks {
322 if (mask & 1) != 0 {
323 for ch in 0..channels {
324 for i in 0..self.blk_align {
325 dst[off[ch] + i] = 0;
326 }
327 off[ch] += self.blk_align;
328 }
329 } else {
330 let mut pred: [i32; 2] = [0; 2];
331 for ch in 0..channels {
332 pred[ch] = i32::from(br.read_u16le()?);
333 dst[off[ch]] = pred[ch] as i16;
334 off[ch] += 1;
335 }
336 let mut ch = 0;
337 let flip_ch = if channels == 2 { 1 } else { 0 };
338 for _ in channels..self.blk_align*channels {
339 let b = br.read_byte()? as usize;
340 if (b & 0x80) != 0 {
341 pred[ch] -= i32::from(SOL_AUD_STEPS16[b & 0x7F]);
342 } else {
343 pred[ch] += i32::from(SOL_AUD_STEPS16[b & 0x7F]);
344 }
345 //pred[ch] = pred[ch].max(-32768).min(32767);
346 dst[off[ch]] = pred[ch] as i16;
347 off[ch] += 1;
348 ch ^= flip_ch;
349 }
350 }
351 mask >>= 1;
352 }
353 validate!(br.left() == 0);
354 Ok(())
355 }
356 }
357
358 impl NADecoder for VMDAudioDecoder {
359 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
360 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
361 let fmt;
362 if ainfo.get_format().get_bits() == 8 {
363 fmt = SND_U8_FORMAT;
364 self.is16bit = false;
365 self.blk_size = ainfo.get_block_len();
366 self.blk_align = ainfo.get_block_len() / (ainfo.get_channels() as usize);
367 } else {
368 fmt = SND_S16P_FORMAT;
369 self.is16bit = true;
370 self.blk_size = (ainfo.get_block_len() + 1) * (ainfo.get_channels() as usize);
371 self.blk_align = ainfo.get_block_len();
372 };
373 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
374 self.chmap = NAChannelMap::from_str(if ainfo.get_channels() == 1 { "C" } else { "L,R" }).unwrap();
375 Ok(())
376 } else {
377 Err(DecoderError::InvalidData)
378 }
379 }
380 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
381 let info = pkt.get_stream().get_info();
382 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
383 let pktbuf = pkt.get_buffer();
384 validate!(pktbuf.len() >= 6);
385 let mut mr = MemoryReader::new_read(&pktbuf);
386 let mut br = ByteReader::new(&mut mr);
387 let blk_type = br.read_byte()?;
388 br.read_skip(9)?;
389 let mask;
390 let nblocks;
391 if blk_type == 2 { // initial
392 mask = br.read_u32le()?;
393 nblocks = (mask.count_ones() as usize) + (pktbuf.len() - 14) / self.blk_size;
394 } else if blk_type == 3 { // silence
395 mask = 1;
396 nblocks = 1;
397 } else {
398 mask = 0;
399 nblocks = 1;
400 }
401 let samples = nblocks * self.blk_align;
402 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
403 if self.is16bit {
404 let mut adata = abuf.get_abuf_i16().unwrap();
405 let off1 = adata.get_offset(1);
406 let mut dst = adata.get_data_mut().unwrap();
407 self.decode_16bit(&mut dst, off1, &mut br, nblocks, mask)?;
408 } else {
409 let mut adata = abuf.get_abuf_u8().unwrap();
410 let dst = adata.get_data_mut().unwrap();
411 let mut doff = 0;
412 let mut mask = mask;
413 let channels = self.chmap.num_channels();
414 for _ in 0..nblocks {
415 if (mask & 1) != 0 {
416 for i in 0..self.blk_align * channels {
417 dst[doff + i] = 0;
418 }
419 } else if channels == 1 {
420 for i in 0..self.blk_size {
421 dst[doff + i] = br.read_byte()?;
422 }
423 } else {
424 for i in 0..self.blk_size {
425 let val = br.read_byte()?;
426 if val < 128 {
427 dst[doff + i] = 127 - val;
428 } else {
429 dst[doff + i] = val;
430 }
431 }
432 }
433 doff += self.blk_align * channels;
434 mask >>= 1;
435 }
436 }
437
438 let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
439 frm.set_duration(Some(samples as u64));
440 frm.set_keyframe(true);
441 Ok(frm.into_ref())
442 } else {
443 Err(DecoderError::InvalidData)
444 }
445 }
446 fn flush(&mut self) {
447 }
448 }
449
450 pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
451 Box::new(VMDAudioDecoder::new())
452 }
453
454 #[cfg(test)]
455 mod test {
456 use nihav_core::codecs::RegisteredDecoders;
457 use nihav_core::demuxers::RegisteredDemuxers;
458 use nihav_codec_support::test::dec_video::*;
459 use crate::game_register_all_codecs;
460 use crate::game_register_all_demuxers;
461 #[test]
462 fn test_vmd_video() {
463 let mut dmx_reg = RegisteredDemuxers::new();
464 game_register_all_demuxers(&mut dmx_reg);
465 let mut dec_reg = RegisteredDecoders::new();
466 game_register_all_codecs(&mut dec_reg);
467
468 // let file = "assets/Game/1491.VMD";
469 let file = "assets/Game/128.vmd";
470 test_file_decoding("vmd", file, Some(10), true, false, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
471 }
472 #[test]
473 fn test_vmd_audio() {
474 let mut dmx_reg = RegisteredDemuxers::new();
475 game_register_all_demuxers(&mut dmx_reg);
476 let mut dec_reg = RegisteredDecoders::new();
477 game_register_all_codecs(&mut dec_reg);
478
479 // let file = "assets/Game/1491.VMD";
480 let file = "assets/Game/128.vmd";
481 // let file = "assets/Game/1000.VMD";
482 // let file = "assets/Game/235.VMD";
483 test_decode_audio("vmd", file, None, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
484 }
485 }