use nihav_core::io::byteio::*;
use std::str::FromStr;
+const BMV_INTRA: u8 = 0x03;
+const BMV_SCROLL: u8 = 0x04;
+const BMV_PAL: u8 = 0x08;
+const BMV_COMMAND: u8 = 0x10;
+const BMV_PRINT: u8 = 0x80;
+
+const BMV_MAX_WIDTH: usize = 640;
+const BMV_MAX_HEIGHT: usize = 432;
+const BMV_MAX_SIZE: usize = BMV_MAX_WIDTH * (BMV_MAX_HEIGHT + 1);
+
+enum BMV3Mode {
+ Normal,
+ Copy,
+ Pixfunc,
+ After0,
+ After1,
+ After1C,
+ After4,
+ After5,
+}
+
+struct NibbleReader {
+ nib: u8,
+ has_nib: bool,
+}
+
+impl NibbleReader {
+ fn new() -> Self {
+ Self { nib: 0, has_nib: false }
+ }
+ fn get_nib(&mut self, br: &mut ByteReader) -> DecoderResult<u8> {
+ if self.has_nib {
+ self.has_nib = false;
+ Ok(self.nib)
+ } else {
+ let b = br.read_byte()?;
+ self.nib = b >> 4;
+ self.has_nib = true;
+ Ok(b & 0xF)
+ }
+ }
+ fn get_length(&mut self, br: &mut ByteReader, mut len: usize, mut shift: u8) -> DecoderResult<usize> {
+ loop {
+ let nib = self.get_nib(br)? as usize;
+ len |= nib << shift;
+ shift += 2;
+ if (nib & 0xC) != 0 {
+ return Ok(len - 1);
+ }
+ }
+ }
+ fn push(&mut self, val: u8) {
+ if self.has_nib {
+ panic!("nibble already in cache");
+ } else {
+ self.nib = val;
+ self.has_nib = true;
+ }
+ }
+ fn reset(&mut self) {
+ self.nib = 0;
+ self.has_nib = false;
+ }
+}
+
+struct BMV3VideoDecoder {
+ info: Rc<NACodecInfo>,
+ stride: usize,
+ height: usize,
+ frame: Vec<u16>,
+ prev_frame: Vec<u16>,
+ pixels: [u16; 256],
+ pixbuf: [[u16; 256]; 7],
+ mode: BMV3Mode,
+ pos: usize,
+ end: usize,
+ nr: NibbleReader,
+ is_intra: bool,
+}
+
+impl BMV3VideoDecoder {
+ fn new() -> Self {
+ let dummy_info = Rc::new(DUMMY_CODEC_INFO);
+ let mut frame1 = Vec::with_capacity(BMV_MAX_SIZE);
+ frame1.resize(BMV_MAX_SIZE, 0);
+ let mut frame2 = Vec::with_capacity(BMV_MAX_SIZE);
+ frame2.resize(BMV_MAX_SIZE, 0);
+
+ let mut pixels = [0u16; 256];
+ for (i, el) in pixels.iter_mut().enumerate() {
+ *el = i as u16;
+ }
+ let mut pixbuf = [[0u16; 256]; 7];
+ for i in 0..7 {
+ for j in 0..256 {
+ pixbuf[i][j] = ((i << 8) + j + 0xF8) as u16;
+ }
+ }
+
+ Self {
+ info: dummy_info,
+ stride: 0,
+ height: 0,
+ frame: frame1,
+ prev_frame: frame2,
+ pixels, pixbuf,
+ mode: BMV3Mode::Normal,
+ pos: 0,
+ end: 0,
+ nr: NibbleReader::new(),
+ is_intra: false,
+ }
+ }
+ fn decode_frame(&mut self, br: &mut ByteReader) -> DecoderResult<()> {
+ let mut idx = 0;
+ loop {
+ let op = br.read_byte()?;
+ let mut len;
+ let skip;
+ if op < 0x90 {
+ let op2 = br.read_u16le()?;
+ skip = ((op2 >> 12) as usize) | ((op << 4) as usize);
+ len = (op2 & 0xFFF) as usize;
+ } else {
+ len = ((op & 7) + 1) as usize;
+ skip = ((op >> 3) - 0x11) as usize;
+ }
+ while (idx < 0xF8) && (len > 0) {
+ self.pixels[idx] = br.read_u16le()?;
+ idx += 1;
+ len -= 1;
+ }
+ while (idx < 0x7F8) && (len > 0) {
+ let nidx = idx - 0xF8;
+ self.pixbuf[nidx >> 8][nidx & 0xFF] = br.read_u16le()?;
+ idx += 1;
+ len -= 1;
+ }
+ validate!(len == 0);
+ if skip == 0 { break; }
+ idx += skip;
+ }
+ self.nr.reset();
+ self.mode = BMV3Mode::Normal;
+ while br.left() > 0 && self.pos < self.end {
+ match self.mode {
+ BMV3Mode::Normal => {
+ let op = br.read_byte()?;
+ self.decode_normal(br, op)?;
+ },
+ BMV3Mode::Copy => {
+ let op = br.read_byte()?;
+ if (op & 1) == 0 {
+ self.decode_normal(br, op + 1)?;
+ } else {
+ self.decode_copy(br, op)?;
+ }
+ },
+ BMV3Mode::Pixfunc => {
+ let op = br.read_byte()?;
+ if (op & 1) == 0 {
+ self.decode_copy(br, op + 1)?;
+ } else {
+ self.decode_normal(br, op - 1)?;
+ }
+ },
+ BMV3Mode::After0 => {
+ let cur_op = self.nr.get_nib(br)?;
+ if cur_op < 4 {
+ let op = self.nr.get_nib(br)?;
+ match cur_op {
+ 0 => self.decode_mode5c(br, op | 0x10)?,
+ 1 => self.decode_mode4 (br, op | 0x10)?,
+ 2 => self.decode_mode5c(br, op | 0x30)?,
+ _ => self.decode_mode4 (br, op | 0x30)?,
+ };
+ } else {
+ let len = (cur_op >> 1) - 1;
+ if (cur_op & 1) == 0 {
+ self.pixfunc(br, len as usize)?;
+ } else {
+ self.repeat(len as usize)?;
+ }
+ }
+ }
+ BMV3Mode::After1 => {
+ let cur_op = self.nr.get_nib(br)?;
+ if cur_op < 4 {
+ let op = self.nr.get_nib(br)?;
+ match cur_op {
+ 0 => self.decode_mode4 (br, op | 0x10)?,
+ 1 => self.decode_mode5c(br, op | 0x00)?,
+ 2 => self.decode_mode4 (br, op | 0x30)?,
+ _ => self.decode_mode5c(br, op | 0x20)?,
+ };
+ } else {
+ let len = (cur_op >> 1) - 1;
+ if (cur_op & 1) == 0 {
+ self.repeat(len as usize)?;
+ } else {
+ self.copy(len as usize)?;
+ }
+ }
+ },
+ BMV3Mode::After1C => {
+ let cur_op = self.nr.get_nib(br)?;
+ if cur_op < 4 {
+ let cur_op1 = self.nr.get_nib(br)?;
+ let m5_op = cur_op1 | (cur_op << 4);
+ self.decode_mode5c(br, m5_op)?;
+ } else if (cur_op & 1) == 0 {
+ let len = (cur_op >> 1) - 1;
+ self.copy(len as usize)?;
+ } else {
+ let len = (cur_op >> 1) - 1;
+ self.pixfunc(br, len as usize)?;
+ }
+ },
+ BMV3Mode::After4 => {
+ let cur_op0 = self.nr.get_nib(br)?;
+ let cur_op1 = self.nr.get_nib(br)?;
+ let cur_op = (cur_op0 << 4) | cur_op1;
+ if (cur_op & 0x10) == 0 {
+ self.decode_mode5c(br, cur_op | 0x10)?;
+ } else {
+ self.decode_mode4(br, cur_op)?;
+ }
+ },
+ BMV3Mode::After5 => {
+ let cur_op0 = self.nr.get_nib(br)?;
+ let cur_op1 = self.nr.get_nib(br)?;
+ let cur_op = (cur_op0 << 4) | cur_op1;
+ if (cur_op & 0x10) == 0 {
+ self.decode_mode4(br, cur_op | 0x10)?;
+ } else {
+ self.decode_mode5c(br, cur_op ^ 0x10)?;
+ }
+ },
+ };
+ if self.pos >= self.end { break; }
+ }
+ Ok(())
+ }
+
+ fn copy(&mut self, len: usize) -> DecoderResult<()> {
+ validate!(len <= self.end - self.pos);
+ if self.is_intra {
+ for _ in 0..len {
+ self.frame[self.pos] = self.frame[self.pos - self.stride];
+ self.pos += 1;
+ }
+ } else {
+ for _ in 0..len {
+ self.frame[self.pos] = self.prev_frame[self.pos];
+ self.pos += 1;
+ }
+ }
+ self.mode = BMV3Mode::Copy;
+ Ok(())
+ }
+ fn pixfunc(&mut self, br: &mut ByteReader, len: usize) -> DecoderResult<()> {
+ validate!(len <= self.end - self.pos);
+ for _ in 0..len {
+ let op = BMV_PIXFUNCS_MAP[br.read_byte()? as usize];
+ let val;
+ if op == 0xFF {
+ val = br.read_u16le()?;
+ } else if op >= 0xF8 {
+ let tab_idx = (op - 0xF8) as usize;
+ let sub_idx = br.read_byte()? as usize;
+ val = self.pixbuf[tab_idx][sub_idx];
+ } else {
+ val = self.pixels[op as usize];
+ }
+ self.frame[self.pos] = val;
+ self.pos += 1;
+ }
+ self.mode = BMV3Mode::Pixfunc;
+ Ok(())
+ }
+ fn repeat(&mut self, len: usize) -> DecoderResult<()> {
+ validate!(self.pos > 0);
+ validate!(len <= self.end - self.pos);
+ let pix = self.frame[self.pos - 1];
+ for _ in 0..len {
+ self.frame[self.pos] = pix;
+ self.pos += 1;
+ }
+ self.mode = BMV3Mode::Normal;
+ Ok(())
+ }
+
+ fn decode_normal(&mut self, br: &mut ByteReader, op: u8) -> DecoderResult<()> {
+ if op < 0x40 {
+ let mode = op & 1;
+ let len = ((op >> 1) & 0x7) as usize;
+ if len < 2 {
+ let mut len = (op >> 3) as usize;
+ if (op & 0xF) >= 2 {
+ len += 1;
+ }
+ len = self.nr.get_length(br, len, 3)?;
+ if (op & 1) == 0 {
+ self.copy(len)?;
+ if self.nr.has_nib {
+ self.mode = BMV3Mode::After0;
+ }
+ } else {
+ self.pixfunc(br, len)?;
+ if self.nr.has_nib {
+ self.mode = BMV3Mode::After1;
+ }
+ }
+ } else if mode == 0 {
+ self.copy(len - 1)?;
+ self.nr.push(op >> 4);
+ self.mode = BMV3Mode::After4;
+ } else {
+ self.pixfunc(br, len - 1)?;
+ self.nr.push(op >> 4);
+ self.mode = BMV3Mode::After5;
+ }
+ return Ok(());
+ }
+ let x_op = (op >> 4) as usize;
+ let y_op = ((op >> 1) & 7) as usize;
+ let flag = (op & 1) as usize;
+ if y_op == 0 || y_op == 1 {
+ let len = x_op * 2 - 1 + y_op;
+ if flag == 0 {
+ self.copy(len)?;
+ } else {
+ self.pixfunc(br, len)?;
+ }
+ } else {
+ let len1 = y_op - 1;
+ let len2 = (x_op >> 1) - 1;
+ if flag == 0 {
+ self.copy(len1)?;
+ } else {
+ self.pixfunc(br, len1)?;
+ }
+ match (x_op & 1) * 2 + flag {
+ 0 => self.pixfunc(br, len2)?,
+ 1 => self.repeat(len2)?,
+ 2 => self.repeat(len2)?,
+ _ => self.copy(len2)?,
+ };
+ }
+ Ok(())
+ }
+ fn decode_copy(&mut self, br: &mut ByteReader, op: u8) -> DecoderResult<()> {
+ if op < 0x40 {
+ let len = ((op >> 1) & 0x7) as usize;
+ if len < 2 {
+ let mut len = (op >> 3) as usize;
+ if (op & 0xF) >= 2 {
+ len += 1;
+ }
+ len = self.nr.get_length(br, len, 3)?;
+ self.repeat(len)?;
+ if self.nr.has_nib {
+ self.mode = BMV3Mode::After1C;
+ }
+ } else {
+ self.repeat(len - 1)?;
+ if br.left() == 0 { return Ok(()); }
+ let op2 = self.nr.get_nib(br)?;
+ let cur_op = (op & 0xF0) | op2;
+ self.decode_mode5c(br, cur_op)?;
+ }
+ return Ok(());
+ }
+ let x_op = (op >> 4) as usize;
+ let y_op = ((op >> 1) & 7) as usize;
+ if y_op == 0 || y_op == 1 {
+ self.repeat(x_op * 2 - 1 + y_op)?;
+ } else {
+ self.repeat(y_op - 1)?;
+ let len = (x_op >> 1) - 1;
+ if (x_op & 1) == 0 {
+ self.copy(len)?;
+ } else {
+ self.pixfunc(br, len)?;
+ }
+ }
+ Ok(())
+ }
+ fn decode_mode4(&mut self, br: &mut ByteReader, op: u8) -> DecoderResult<()> {
+ if (op & 0xF) < 4 {
+ let mut len = ((op & 3) * 2) as usize;
+ if (op & 0xF0) >= 0x20 {
+ len += 1;
+ }
+ len = self.nr.get_length(br, len, 3)?;
+ self.repeat(len)?;
+ if self.nr.has_nib {
+ self.mode = BMV3Mode::After1C;
+ }
+ } else {
+ let len = ((op & 0xF) * 2 - 1 + (op >> 5)) as usize;
+ self.repeat(len)?;
+ self.mode = BMV3Mode::After1C;
+ }
+ Ok(())
+ }
+ fn decode_mode5c(&mut self, br: &mut ByteReader, op: u8) -> DecoderResult<()> {
+ if (op & 0xF) < 4 {
+ let mut len = ((op & 3) * 2) as usize;
+ if (op & 0xF0) >= 0x20 {
+ len += 1;
+ }
+ len = self.nr.get_length(br, len, 3)?;
+ if (op & 0x10) == 0 {
+ self.copy(len)?;
+ if self.nr.has_nib {
+ self.mode = BMV3Mode::After0;
+ }
+ } else {
+ self.pixfunc(br, len)?;
+ if self.nr.has_nib {
+ self.mode = BMV3Mode::After1;
+ }
+ }
+ } else {
+ let len = ((op & 0xF) * 2 - 1 + (op >> 5)) as usize;
+ if (op & 0x10) == 0 {
+ self.copy(len)?;
+ self.mode = BMV3Mode::After0;
+ } else {
+ self.pixfunc(br, len)?;
+ self.mode = BMV3Mode::After1;
+ }
+ }
+ Ok(())
+ }
+}
+
+impl NADecoder for BMV3VideoDecoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, RGB565_FORMAT));
+ self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));
+
+ self.stride = vinfo.get_width();
+ self.height = vinfo.get_height();
+ self.end = self.stride * (self.height + 1);
+
+ validate!((self.stride <= 640) && (self.height <= 432));
+
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let src = pkt.get_buffer();
+ validate!(src.len() > 1);
+
+ let mut mr = MemoryReader::new_read(&src);
+ let mut br = ByteReader::new(&mut mr);
+ let flags = br.read_byte()?;
+
+ if (flags & BMV_COMMAND) != 0 {
+ let size = if (flags & BMV_PRINT) != 0 { 8 } else { 10 };
+ br.read_skip(size)?;
+ }
+ if (flags & BMV_PAL) != 0 {
+ return Err(DecoderError::InvalidData);
+ }
+ let off;
+ if ((flags & 1) == 0) && ((flags & BMV_SCROLL) != 0) {
+ off = br.read_u16le()? as usize;
+ } else {
+ off = 0;
+ }
+ self.pos = off + self.stride;
+ self.is_intra = (flags & BMV_INTRA) == BMV_INTRA;
+
+ let bufret = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0);
+ if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
+ let bufinfo = bufret.unwrap();
+
+ self.decode_frame(&mut br)?;
+
+ {
+ let mut buf = bufinfo.get_vbuf16().unwrap();
+ let stride = buf.get_stride(0);
+ let mut data = buf.get_data_mut();
+ let dst = data.as_mut_slice();
+
+ let refbuf = &self.frame[self.stride..];
+ for (dst, src) in dst.chunks_mut(stride).zip(refbuf.chunks(self.stride)).take(self.height) {
+ let out = &mut dst[0..self.stride];
+ out.copy_from_slice(src);
+ }
+ }
+ std::mem::swap(&mut self.frame, &mut self.prev_frame);
+
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(self.is_intra);
+ frm.set_frame_type(if self.is_intra { FrameType::I } else { FrameType::P });
+ Ok(Rc::new(RefCell::new(frm)))
+ }
+}
+
pub fn get_decoder_video() -> Box<NADecoder> {
- unimplemented!();
+ Box::new(BMV3VideoDecoder::new())
}
struct BMV3AudioDecoder {
game_register_all_codecs(&mut dec_reg);
let file = "assets/Game/DW3-Loffnote.bmv";
- test_file_decoding("bmv3", file, Some(40), true, false, None, &dmx_reg, &dec_reg);
+ test_file_decoding("bmv3", file, None, true, false, None, &dmx_reg, &dec_reg);
}
#[test]
fn test_bmv_audio() {
}
}
+const BMV_PIXFUNCS_MAP: [u8; 256] = [
+ 0x38, 0x78, 0xB8, 0xF9,
+ 0x39, 0x79, 0xB9, 0xFA,
+ 0x3A, 0x7A, 0xBA, 0xFB,
+ 0x3B, 0x7B, 0xBB, 0xFC,
+ 0x3C, 0x7C, 0xBC, 0xFD,
+ 0x3D, 0x7D, 0xBD, 0xFE,
+ 0x3E, 0x7E, 0xBE, 0xFF,
+ 0x3F, 0x7F, 0xBF, 0x00,
+ 0x40, 0x80, 0xC0, 0x01,
+ 0x41, 0x81, 0xC1, 0x02,
+ 0x42, 0x82, 0xC2, 0x03,
+ 0x43, 0x83, 0xC3, 0x04,
+ 0x44, 0x84, 0xC4, 0x05,
+ 0x45, 0x85, 0xC5, 0x06,
+ 0x46, 0x86, 0xC6, 0x07,
+ 0x47, 0x87, 0xC7, 0x08,
+ 0x48, 0x88, 0xC8, 0x09,
+ 0x49, 0x89, 0xC9, 0x0A,
+ 0x4A, 0x8A, 0xCA, 0x0B,
+ 0x4B, 0x8B, 0xCB, 0x0C,
+ 0x4C, 0x8C, 0xCC, 0x0D,
+ 0x4D, 0x8D, 0xCD, 0x0E,
+ 0x4E, 0x8E, 0xCE, 0x0F,
+ 0x4F, 0x8F, 0xCF, 0x10,
+ 0x50, 0x90, 0xD0, 0x11,
+ 0x51, 0x91, 0xD1, 0x12,
+ 0x52, 0x92, 0xD2, 0x13,
+ 0x53, 0x93, 0xD3, 0x14,
+ 0x54, 0x94, 0xD4, 0x15,
+ 0x55, 0x95, 0xD5, 0x16,
+ 0x56, 0x96, 0xD6, 0x17,
+ 0x57, 0x97, 0xD7, 0x18,
+ 0x58, 0x98, 0xD8, 0x19,
+ 0x59, 0x99, 0xD9, 0x1A,
+ 0x5A, 0x9A, 0xDA, 0x1B,
+ 0x5B, 0x9B, 0xDB, 0x1C,
+ 0x5C, 0x9C, 0xDC, 0x1D,
+ 0x5D, 0x9D, 0xDD, 0x1E,
+ 0x5E, 0x9E, 0xDE, 0x1F,
+ 0x5F, 0x9F, 0xDF, 0x20,
+ 0x60, 0xA0, 0xE0, 0x21,
+ 0x61, 0xA1, 0xE1, 0x22,
+ 0x62, 0xA2, 0xE2, 0x23,
+ 0x63, 0xA3, 0xE3, 0x24,
+ 0x64, 0xA4, 0xE4, 0x25,
+ 0x65, 0xA5, 0xE5, 0x26,
+ 0x66, 0xA6, 0xE6, 0x27,
+ 0x67, 0xA7, 0xE7, 0x28,
+ 0x68, 0xA8, 0xE8, 0x29,
+ 0x69, 0xA9, 0xE9, 0x2A,
+ 0x6A, 0xAA, 0xEA, 0x2B,
+ 0x6B, 0xAB, 0xEB, 0x2C,
+ 0x6C, 0xAC, 0xEC, 0x2D,
+ 0x6D, 0xAD, 0xED, 0x2E,
+ 0x6E, 0xAE, 0xEE, 0x2F,
+ 0x6F, 0xAF, 0xEF, 0x30,
+ 0x70, 0xB0, 0xF0, 0x31,
+ 0x71, 0xB1, 0xF1, 0x32,
+ 0x72, 0xB2, 0xF2, 0x33,
+ 0x73, 0xB3, 0xF3, 0x34,
+ 0x74, 0xB4, 0xF4, 0x35,
+ 0x75, 0xB5, 0xF5, 0x36,
+ 0x76, 0xB6, 0xF6, 0x37,
+ 0x77, 0xB7, 0xF7, 0xF8
+];
+
const BMV_AUDIO_STEPS: [[i16; 32]; 16] = [
[
0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00,