+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: NACodecInfoRef,
+ 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 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: NACodecInfoRef::default(),
+ stride: 0,
+ height: 0,
+ frame: vec![0; BMV_MAX_SIZE],
+ prev_frame: vec![0; BMV_MAX_SIZE],
+ 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 as usize) << 4);
+ 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, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> 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 = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+ 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, _supp: &mut NADecoderSupport, 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 bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
+
+ self.decode_frame(&mut br)?;
+
+ {
+ let mut buf = bufinfo.get_vbuf16().unwrap();
+ let stride = buf.get_stride(0);
+ let data = buf.get_data_mut().unwrap();
+ 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(frm.into_ref())
+ }
+ fn flush(&mut self) {
+ }
+}
+
+
+pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
+ Box::new(BMV3VideoDecoder::new())