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