--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+
+struct Glyphs {
+ data: [[[u8; 16]; 256]; 2],
+ glyph8: [[u8; 64]; 256],
+ glyph8_init: bool,
+}
+
+impl Glyphs {
+ fn new() -> Self {
+ Self {
+ data: [[[0; 16]; 256]; 2],
+ glyph8: [[0; 64]; 256],
+ glyph8_init: false,
+ }
+ }
+ fn make_glyphs_4(&mut self, mode: u8) {
+ for i in (1..16).step_by(2) {
+ let cy = (i as u8) + mode;
+ for j in 0..16 {
+ let dst = &mut self.data[0][(i / 2) * 16 + j];
+
+ let cx = (j as u8) + mode;
+ let avg = mode + (((i + j) >> 1) as u8);
+ if avg == cx || avg == cy {
+ dst[ 0] = cx; dst[ 1] = cy; dst[ 2] = cx; dst[ 3] = cy;
+ dst[ 4] = cy; dst[ 5] = cx; dst[ 6] = cy; dst[ 7] = cy;
+ dst[ 8] = cx; dst[ 9] = cy; dst[10] = cx; dst[11] = cy;
+ dst[12] = cx; dst[13] = cx; dst[14] = cy; dst[15] = cx;
+ } else {
+ let c0 = avg;
+ let c1 = ((u16::from(avg) + u16::from(cy)) >> 1) as u8;
+ let c2 = ((u16::from(avg) + u16::from(cx)) >> 1) as u8;
+ dst[ 0] = c0; dst[ 1] = c0; dst[ 2] = c1; dst[ 3] = cy;
+ dst[ 4] = c0; dst[ 5] = c0; dst[ 6] = c1; dst[ 7] = cy;
+ dst[ 8] = c2; dst[ 9] = c2; dst[10] = c0; dst[11] = c1;
+ dst[12] = cx; dst[13] = cx; dst[14] = c2; dst[15] = c0;
+ }
+ }
+ }
+ for i in (0..16).step_by(2) {
+ let cy = (i as u8) + mode;
+ for j in 0..16 {
+ let dst = &mut self.data[0][128 + (i / 2) * 16 + j];
+
+ let cx = (j as u8) + mode;
+ let avg = mode + (((i + j) >> 1) as u8);
+ if avg == cx || avg == cy {
+ dst[ 0] = cy; dst[ 1] = cy; dst[ 2] = cx; dst[ 3] = cy;
+ dst[ 4] = cy; dst[ 5] = cy; dst[ 6] = cy; dst[ 7] = cx;
+ dst[ 8] = cx; dst[ 9] = cy; dst[10] = cx; dst[11] = cx;
+ dst[12] = cy; dst[13] = cx; dst[14] = cy; dst[15] = cx;
+ } else {
+ let c1 = ((u16::from(avg) + u16::from(cy)) >> 1) as u8;
+ let c2 = ((u16::from(avg) + u16::from(cx)) >> 1) as u8;
+ dst[ 0] = cy; dst[ 1] = cy; dst[ 2] = c1; dst[ 3] = cx;
+ dst[ 4] = cy; dst[ 5] = cy; dst[ 6] = c1; dst[ 7] = cx;
+ dst[ 8] = c1; dst[ 9] = c1; dst[10] = cx; dst[11] = c2;
+ dst[12] = cx; dst[13] = cx; dst[14] = c2; dst[15] = cx;
+ }
+ }
+ }
+ }
+ fn make_glyphs_5(&mut self, mode: u8) {
+ for i in 0..8 {
+ let cy = (i as u8) + mode;
+ for j in 0..8 {
+ let dst = &mut self.data[0][i * 8 + j];
+
+ let cx = (j as u8) + mode;
+ let avg = mode + (((i + j) >> 1) as u8);
+ let c0 = avg;
+ let c1 = ((u16::from(avg) + u16::from(cy)) >> 1) as u8;
+ let c2 = ((u16::from(avg) + u16::from(cx)) >> 1) as u8;
+
+ dst[ 0] = c0; dst[ 1] = c0; dst[ 2] = c1; dst[ 3] = cy;
+ dst[ 4] = c0; dst[ 5] = c0; dst[ 6] = c1; dst[ 7] = cy;
+ dst[ 8] = c2; dst[ 9] = c2; dst[10] = c0; dst[11] = c1;
+ dst[12] = cx; dst[13] = cx; dst[14] = c2; dst[15] = c0;
+ }
+ }
+ for i in 0..8 {
+ let cy = (i as u8) + mode;
+ for j in 0..8 {
+ let dst = &mut self.data[0][i * 8 + j + 64];
+
+ let cx = (j as u8) + mode;
+ let avg = mode + (((i + j) >> 1) as u8);
+ let c0 = avg;
+ let c2 = ((u16::from(avg) + u16::from(cx)) >> 1) as u8;
+
+ dst[ 0] = cy; dst[ 1] = cy; dst[ 2] = cy; dst[ 3] = cy;
+ dst[ 4] = c0; dst[ 5] = c0; dst[ 6] = c0; dst[ 7] = c0;
+ dst[ 8] = c2; dst[ 9] = c2; dst[10] = c2; dst[11] = c2;
+ dst[12] = cx; dst[13] = cx; dst[14] = cx; dst[15] = cx;
+ }
+ }
+ for i in 0..8 {
+ let cy = (i as u8) + mode;
+ for j in 0..8 {
+ let dst = &mut self.data[0][i * 8 + j + 128];
+
+ let cx = (j as u8) + mode;
+ let avg = mode + (((i + j) >> 1) as u8);
+ let c0 = avg;
+ let c1 = ((u16::from(avg) + u16::from(cy)) >> 1) as u8;
+ let c2 = ((u16::from(avg) + u16::from(cx)) >> 1) as u8;
+
+ dst[ 0] = cy; dst[ 1] = cy; dst[ 2] = c1; dst[ 3] = c0;
+ dst[ 4] = cy; dst[ 5] = cy; dst[ 6] = c1; dst[ 7] = c0;
+ dst[ 8] = c1; dst[ 9] = c1; dst[10] = c0; dst[11] = c2;
+ dst[12] = c0; dst[13] = c0; dst[14] = c2; dst[15] = cx;
+ }
+ }
+ for i in 0..8 {
+ let cy = (i as u8) + mode;
+ for j in 0..8 {
+ let dst = &mut self.data[0][i * 8 + j + 192];
+
+ let cx = (j as u8) + mode;
+ let avg = mode + (((i + j) >> 1) as u8);
+ let c0 = avg;
+ let c2 = ((u16::from(avg) + u16::from(cx)) >> 1) as u8;
+
+ dst[ 0] = cy; dst[ 1] = c0; dst[ 2] = c2; dst[ 3] = cx;
+ dst[ 4] = cy; dst[ 5] = c0; dst[ 6] = c2; dst[ 7] = cx;
+ dst[ 8] = cy; dst[ 9] = c0; dst[10] = c2; dst[11] = cx;
+ dst[12] = cy; dst[13] = c0; dst[14] = c2; dst[15] = cx;
+ }
+ }
+ }
+ fn read_additional(&mut self, br: &mut ByteReader, add: u16) -> DecoderResult<()> {
+ if add > 0 {
+ validate!(add <= 256);
+ let mut gbuf = [0; 8];
+ for glyph in self.data[1].iter_mut().take(add as usize) {
+ br.read_buf(&mut gbuf)?;
+ for (pair, &b) in glyph.chunks_mut(2).zip(gbuf.iter()) {
+ pair[0] = b >> 4;
+ pair[1] = b & 0xF;
+ }
+ }
+ }
+ Ok(())
+ }
+ fn make_glyphs_47(&mut self) {
+ super::make_glyphs_47(&mut self.data[0], &mut self.glyph8);
+ self.glyph8_init = true;
+ }
+}
+
+struct FrameData {
+ info: NACodecInfoRef,
+ pal: [u8; 768],
+ fpal: [u16; 768],
+ pdelta: [u16; 768],
+ width: usize,
+ height: usize,
+ frm0: Vec<u8>,
+ frm1: Vec<u8>,
+ frm2: Vec<u8>,
+}
+
+impl FrameData {
+ fn new() -> Self {
+ Self {
+ info: NACodecInfoRef::default(),
+ pal: [0; 768],
+ fpal: [0; 768],
+ pdelta: [0; 768],
+ width: 0,
+ height: 0,
+ frm0: Vec::new(),
+ frm1: Vec::new(),
+ frm2: Vec::new(),
+ }
+ }
+ fn init(&mut self, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ self.width = vinfo.get_width();
+ self.height = vinfo.get_height();
+self.width = (self.width + 7) & !7;
+self.height = (self.height + 7) & !7;
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, PAL8_FORMAT));
+ self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+ if let Some(edata) = info.get_extradata() {
+ validate!(edata.len() > 768);
+ self.pal.copy_from_slice(&edata[1..][..768]);
+ }
+
+ self.frm0.resize(self.width * self.height, 0);
+ self.frm1.resize(self.width * self.height, 0);
+ self.frm2.resize(self.width * self.height, 0);
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ #[inline]
+ fn set_pixel(&mut self, xoff: i16, yoff: i16, x: usize, y: usize, pix: u8) {
+ let xpos = (xoff as isize) + (x as isize);
+ if xpos < 0 { return; }
+ let xpos = xpos as usize;
+ let ypos = (yoff as isize) + (y as isize);
+ if ypos < 0 { return; }
+ let ypos = ypos as usize;
+ if xpos < self.width && ypos < self.height {
+ self.frm0[xpos + ypos * self.width] = pix;
+ }
+ }
+ fn get_pixel(&mut self, xoff: i16, yoff: i16, x: usize, y: usize) -> u8 {
+ let xpos = (xoff as isize) + (x as isize);
+ if xpos < 0 { return 0; }
+ let xpos = xpos as usize;
+ let ypos = (yoff as isize) + (y as isize);
+ if ypos < 0 { return 0; }
+ let ypos = ypos as usize;
+ if xpos < self.width && ypos < self.height {
+ self.frm0[xpos + ypos * self.width]
+ } else {
+ 0
+ }
+ }
+ fn loop_filter(&mut self, _xoff: i16, _yoff: i16, _x: usize, _y: usize) {
+/* let xpos = (xoff as isize) + (x as isize);
+ if xpos < 0 { return; }
+ let xpos = xpos as usize;
+ let ypos = (yoff as isize) + (y as isize);
+ if ypos < 0 { return; }
+ let ypos = ypos as usize;
+ if xpos < self.width && ypos < self.height {
+ let start = xpos + ypos * self.width;
+ if xpos > 0 {
+ for row in self.frm0[start - 1..].chunks_mut(self.width).take(4) {
+ let x0 = row[0];
+ let x1 = row[1];
+ row[1] = 0x80 | (x0.wrapping_add(x1) >> 1);
+ }
+ }
+ if ypos > 0 {
+ for i in 0..4 {
+ let y0 = self.frm0[start + i];
+ let y1 = &mut self.frm0[start + i + self.width];
+ *y1 = 0x80 | (y1.wrapping_add(y0) >> 1);
+ }
+ }
+ }*/
+ }
+ fn get_frame(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
+ if let Some(ref mut vbuf) = bufinfo.get_vbuf() {
+ let stride = vbuf.get_stride(0);
+ let paloff = vbuf.get_offset(1);
+ let data = vbuf.get_data_mut().unwrap();
+ for (dst, src) in data.chunks_mut(stride).zip(self.frm0.chunks(self.width).take(self.height)) {
+ dst[..self.width].copy_from_slice(src);
+ }
+ data[paloff..][..768].copy_from_slice(&self.pal);
+ } else {
+ return Err(DecoderError::Bug);
+ }
+
+ let is_intra = pkt.keyframe;
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(is_intra);
+ frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
+ Ok(frm.into_ref())
+ }
+}
+
+fn do_mc(dst: &mut [u8], src: &[u8], stride: usize, xoff: isize, yoff: isize, w: usize, h: usize) {
+ let mut pos = xoff + yoff * (stride as isize);
+ for row in dst.chunks_mut(stride).take(4) {
+ for i in 0..4 {
+ row[i] = if pos >= 0 && (pos as usize) < w + (h - 1) * stride {
+ src[pos as usize]
+ } else { 0 };
+ pos += 1;
+ }
+ pos -= 4;
+ pos += stride as isize;
+ }
+}
+
+#[allow(clippy::too_many_arguments)]
+fn do_block47(br: &mut ByteReader, dst: &mut [u8], frm1: &[u8], frm2: &[u8], x: usize, y: usize, stride: usize, bsize: usize, clr: &[u8; 6], glyphs: &Glyphs) -> DecoderResult<()> {
+ let op = br.read_byte()?;
+ match op {
+ 0xFF if bsize > 2 => {
+ let hsize = bsize / 2;
+ do_block47(br, dst, frm1, frm2, x, y, stride, hsize, clr, glyphs)?;
+ do_block47(br, &mut dst[hsize..], frm1, frm2, x + hsize, y, stride, bsize / 2, clr, glyphs)?;
+ do_block47(br, &mut dst[hsize * stride..], frm1, frm2, x, y + hsize, stride, hsize, clr, glyphs)?;
+ do_block47(br, &mut dst[hsize * (stride + 1)..], frm1, frm2, x + hsize, y + hsize, stride, bsize / 2, clr, glyphs)?;
+ },
+ 0xFF => {
+ br.read_buf(&mut dst[..2])?;
+ br.read_buf(&mut dst[stride..][..2])?;
+ },
+ 0xFE => {
+ let pix = br.read_byte()?;
+ for dst in dst.chunks_mut(stride).take(bsize) {
+ for el in dst[..bsize].iter_mut() {
+ *el = pix;
+ }
+ }
+ },
+ 0xFD => {
+ let idx = br.read_byte()? as usize;
+ let mut clr = [0; 2];
+ clr[1] = br.read_byte()?;
+ clr[0] = br.read_byte()?;
+ let mut glyph = if bsize == 8 { glyphs.glyph8[idx].iter() } else { glyphs.data[0][idx].iter() };
+
+ for dst in dst.chunks_mut(stride).take(bsize) {
+ for el in dst[..bsize].iter_mut() {
+ *el = clr[*glyph.next().unwrap_or(&0) as usize];
+ }
+ }
+ },
+ 0xFC => {
+ let off = x + y * stride;
+ let src = &frm1[off..];
+ for (dst, src) in dst.chunks_mut(stride).zip(src.chunks(stride)).take(bsize) {
+ dst[..bsize].copy_from_slice(&src[..bsize]);
+ }
+ },
+ 0xF8..=0xFB => {
+ let pix = clr[(op & 7) as usize];
+ for dst in dst.chunks_mut(stride).take(bsize) {
+ for el in dst[..bsize].iter_mut() {
+ *el = pix;
+ }
+ }
+ },
+ _ => {
+ let mx = C47_MV[0][op as usize][0] as isize;
+ let my = C47_MV[0][op as usize][1] as isize;
+ let off = (x as isize) + mx + ((y as isize) + my) * (stride as isize);
+ validate!(off >= 0);
+ let src = &frm2[off as usize..];
+ for (dst, src) in dst.chunks_mut(stride).zip(src.chunks(stride)).take(bsize) {
+ dst[..bsize].copy_from_slice(&src[..bsize]);
+ }
+ },
+ };
+ Ok(())
+}
+
+macro_rules! c48_mv {
+ (index; $dst: expr, $src: expr, $br: expr, $x: expr, $y: expr, $stride: expr, $size: expr, $mvsel: expr) => ({
+ for yy in (0..8).step_by($size) {
+ for xx in (0..8).step_by($size) {
+ let idx = $br.read_byte()? as usize;
+ validate!(idx < 255);
+ let mx = C47_MV[$mvsel][idx][0] as isize;
+ let my = C47_MV[$mvsel][idx][1] as isize;
+ c48_mv!(common; &mut $dst[xx + yy * $stride..], $src, $x + xx, $y + yy, mx, my, $stride, $size)
+ }
+ }
+
+ });
+ (offset; $dst: expr, $src: expr, $br: expr, $x: expr, $y: expr, $w: expr, $stride: expr, $size: expr) => ({
+ for yy in (0..8).step_by($size) {
+ for xx in (0..8).step_by($size) {
+ let offset = $br.read_u16le()? as i16 as isize;
+ let mx = offset % ($w as isize);
+ let my = offset / ($w as isize);
+ c48_mv!(common; &mut $dst[xx + yy * $stride..], $src, $x + xx, $y + yy, mx, my, $stride, $size)
+ }
+ }
+ });
+ (common; $dst: expr, $src: expr, $x: expr, $y: expr, $mx: expr, $my: expr, $stride: expr, $size: expr) => {{
+ let srcpos = ($x as isize) + $mx + (($y as isize) + $my) * ($stride as isize);
+ validate!(srcpos >= 0);
+ for (dst, src) in $dst.chunks_mut($stride).zip($src[srcpos as usize..].chunks($stride)).take($size) {
+ let size = dst.len().min(src.len()).min($size);
+ dst[..size].copy_from_slice(&src[..size]);
+ }
+ }}
+}
+
+fn scale2x(block: &[u8; 16], dst: &mut [u8], stride: usize) {
+ for (drow, src) in dst.chunks_mut(stride * 2).zip(block.chunks_exact(4)) {
+ for row in drow.chunks_mut(stride) {
+ for (dpair, &el) in row.chunks_exact_mut(2).zip(src.iter()) {
+ dpair[0] = el;
+ dpair[1] = el;
+ }
+ }
+ }
+}
+
+struct Smush1Decoder {
+ glyphs: Glyphs,
+ pic: FrameData,
+ version: u8,
+ prev_seq: u16,
+ reorder: u8,
+ filter: [[u8; 256]; 256],
+}
+
+impl Smush1Decoder {
+ fn new() -> Self {
+ Self {
+ glyphs: Glyphs::new(),
+ pic: FrameData::new(),
+ version: 0,
+ prev_seq: 0,
+ reorder: 0,
+ filter: [[0; 256]; 256],
+ }
+ }
+
+ fn decode_rle(br: &mut ByteReader, dst: &mut [u8], w: usize, h: usize, stride: usize) -> DecoderResult<()> {
+ let mut x = 0;
+ let mut y = 0;
+ let mut len = 0;
+ let mut clr = 0;
+ let mut run = false;
+ while (x != 0) || (y != h) {
+ if len == 0 {
+ let op = br.read_byte()?;
+ run = (op & 1) != 0;
+ if run {
+ clr = br.read_byte()?;
+ }
+ len = ((op >> 1) + 1) as usize;
+ }
+ if run {
+ dst[x + y * stride] = clr;
+ } else {
+ dst[x + y * stride] = br.read_byte()?;
+ }
+ len -= 1;
+ x += 1;
+ if x == w {
+ x = 0;
+ y += 1;
+ }
+ }
+ validate!(len == 0);
+
+ Ok(())
+ }
+
+ fn decode_1(&mut self, br: &mut ByteReader, x: i16, y: i16, w: usize, h: usize, transparent: bool) -> DecoderResult<()> {
+ for yy in 0..h {
+ let len = u64::from(br.read_u16le()?);
+ let end = br.tell() + len;
+ let mut xx = 0;
+ while (br.tell() < end) && (xx < w) {
+ let op = br.read_byte()?;
+ let len = ((op >> 1) + 1) as usize;
+ if (op & 1) == 0 {
+ for _ in 0..len {
+ let clr = br.read_byte()?;
+ if !transparent || clr != 0 {
+ self.pic.set_pixel(x, y, xx, yy, clr);
+ }
+ xx += 1;
+ }
+ } else {
+ let clr = br.read_byte()?;
+ if !transparent || clr != 0 {
+ for _ in 0..len {
+ self.pic.set_pixel(x, y, xx, yy, clr);
+ xx += 1;
+ }
+ } else {
+ xx += len;
+ }
+ }
+ }
+ validate!(br.tell() == end && xx == w);
+ }
+
+ Ok(())
+ }
+ #[allow(clippy::verbose_bit_mask)]
+ fn decode_2(&mut self, br: &mut ByteReader, x: i16, y: i16, _w: usize, _h: usize, len: usize) -> DecoderResult<()> {
+
+ validate!((len & 3) == 0);
+ let mut xpos = x;
+ let mut ypos = y;
+ for _ in 0..len/4 {
+ let xoff = br.read_u16le()? as i16;
+ let yoff = i16::from(br.read_byte()?);
+ let pix = br.read_byte()?;
+
+ xpos += xoff;
+ ypos += yoff;
+ self.pic.set_pixel(xpos, ypos, 0, 0, pix);
+ }
+ Ok(())
+ }
+ #[allow(clippy::too_many_arguments)]
+ fn decode_4(&mut self, br: &mut ByteReader, x: i16, y: i16, w: usize, h: usize, mode: u8, add: u16) -> DecoderResult<()> {
+ self.glyphs.make_glyphs_4(mode);
+ self.glyphs.read_additional(br, add)?;
+
+ for col in (0..w).step_by(4) {
+ let mut mask = 0;
+ let mut bits = 0;
+ for row in (0..h).step_by(4) {
+ let bit = if add > 0 {
+ if bits == 0 {
+ mask = br.read_byte()?;
+ bits = 8;
+ }
+ let bit = (mask & 0x80) != 0;
+ mask <<= 1;
+ bits -= 1;
+ bit
+ } else {
+ false
+ };
+
+ let tile_no = br.read_byte()? as usize;
+ if !bit && (tile_no == 0x80) {
+ continue;
+ }
+ let src = &self.glyphs.data[bit as usize][tile_no];
+ for (y1, srow) in src.chunks(4).enumerate() {
+ for (x1, &pix) in srow.iter().enumerate() {
+ self.pic.set_pixel(x, y, col + x1, row + y1, pix);
+ }
+ }
+ if !bit {
+ self.pic.loop_filter(x, y, col, row);
+ }
+ }
+ }
+
+ Ok(())
+ }
+ #[allow(clippy::too_many_arguments)]
+ fn decode_5(&mut self, br: &mut ByteReader, x: i16, y: i16, w: usize, h: usize, mode: u8, add: u16) -> DecoderResult<()> {
+ self.glyphs.make_glyphs_5(mode);
+ self.glyphs.read_additional(br, add)?;
+
+ for col in (0..w).step_by(4) {
+ let mut mask = 0;
+ let mut bits = 0;
+ for row in (0..h).step_by(4) {
+ let bit = if add > 0 {
+ if bits == 0 {
+ mask = br.read_byte()?;
+ bits = 8;
+ }
+ let bit = (mask & 0x80) != 0;
+ mask <<= 1;
+ bits -= 1;
+ bit
+ } else {
+ false
+ };
+
+ let tile_no = br.read_byte()? as usize;
+ let src = &self.glyphs.data[bit as usize][tile_no];
+ for (y1, srow) in src.chunks(4).enumerate() {
+ for (x1, &pix) in srow.iter().enumerate() {
+ self.pic.set_pixel(x, y, col + x1, row + y1, pix);
+ }
+ }
+ if !bit {
+ self.pic.loop_filter(x, y, col, row);
+ }
+ }
+ }
+
+ Ok(())
+ }
+ fn decode_21(&mut self, br: &mut ByteReader, x: i16, y: i16, w: usize, h: usize, size: usize) -> DecoderResult<()> {
+ let end = br.tell() + (size as u64);
+ for yy in 0..h {
+ if br.tell() >= end { break; }
+ let len = u64::from(br.read_u16le()?);
+ let end = br.tell() + len;
+ let mut xx = 0;
+ let mut skip = true;
+ while (br.tell() < end) && (xx <= w) {
+ let len = br.read_u16le()? as usize;
+ if !skip {
+ for _ in 0..=len {
+ let pix = br.read_byte()?;
+ self.pic.set_pixel(x, y, xx, yy, pix);
+ xx += 1;
+ }
+ } else {
+ for _ in 0..len {
+ self.pic.set_pixel(x, y, xx, yy, 0);
+ xx += 1;
+ }
+ }
+ skip = !skip;
+ }
+ validate!(br.tell() == end && xx == w + 1);
+ }
+
+ Ok(())
+ }
+ #[allow(clippy::too_many_arguments)]
+ fn decode_23(&mut self, br: &mut ByteReader, x: i16, y: i16, w: usize, h: usize, bias: u8, add: u16, old: bool) -> DecoderResult<()> {
+ let mut lut = [0; 256];
+ if old {
+ for (i, el) in lut.iter_mut().enumerate() {
+ *el = (i as u8).wrapping_add(bias.wrapping_sub(0x30));
+ }
+ } else if add != 256 {
+ for (i, el) in lut.iter_mut().enumerate() {
+ *el = (i as u8).wrapping_add(add as u8);
+ }
+ } else {
+ br.read_buf(&mut lut)?;
+ }
+ for yy in 0..h {
+ let len = u64::from(br.read_u16le()?);
+ let end = br.tell() + len;
+ let mut xx = 0;
+ let mut skip = true;
+ while (br.tell() < end) && (xx <= w) {
+ let len = br.read_byte()? as usize;
+ if !skip {
+ for _ in 0..len {
+ let pix = self.pic.get_pixel(x, y, xx, yy);
+ self.pic.set_pixel(x, y, xx, yy, lut[pix as usize]);
+ xx += 1;
+ }
+ } else {
+ xx += len;
+ }
+ skip = !skip;
+ }
+ validate!(br.tell() == end && xx == w + 1);
+ }
+
+ Ok(())
+ }
+ fn decode_37(&mut self, br: &mut ByteReader, x: i16, y: i16, mut w: usize, mut h: usize) -> DecoderResult<()> {
+ let compr = br.read_byte()?;
+ let mv_off = br.read_byte()? as usize;
+ validate!(mv_off <= 2);
+ let seq = br.read_u16le()?;
+ let _unp_size = br.read_u32le()?;
+ let _packed_size = br.read_u32le()?;
+ let flags = br.read_byte()?;
+ br.read_skip(3)?;
+
+ w = (w + 3) & !3;
+ h = (h + 3) & !3;
+
+ validate!(x >= 0 && y >= 0);
+ let x = x as usize;
+ let y = y as usize;
+ validate!((x + w <= self.pic.width) && (y + h <= self.pic.height));
+
+ if compr == 0 || compr == 2 {
+ for el in self.pic.frm1.iter_mut() {
+ *el = 0;
+ }
+ for el in self.pic.frm2.iter_mut() {
+ *el = 0;
+ }
+ } else if ((seq & 1) != 0) || ((flags & 1) == 0) {
+ std::mem::swap(&mut self.pic.frm0, &mut self.pic.frm2);
+ }
+
+ let stride = self.pic.width;
+ let dst = &mut self.pic.frm0[x + y * stride..];
+ let prv = &self.pic.frm2[x + y * stride..];
+ match compr {
+ 0 => {
+ for line in dst.chunks_mut(stride).take(h) {
+ br.read_buf(&mut line[..w])?;
+ }
+ },
+ 1 => {
+ let mut len = -1;
+ let mut run = false;
+ let mut code = 0;
+ for (row_no, row) in dst.chunks_mut(stride * 4).take(h / 4).enumerate() {
+ for col in (0..w).step_by(4) {
+ let skip_code = if len < 0 {
+ let op = br.read_byte()?;
+ len = (op >> 1) as i8;
+ run = (op & 1) != 0;
+ false
+ } else {
+ run
+ };
+ if !skip_code {
+ code = br.read_byte()?;
+ if code == 0xFF {
+ len -= 1;
+ for drow in row[col..].chunks_mut(stride) {
+ for el in drow[..4].iter_mut() {
+ if len < 0 {
+ let op = br.read_byte()?;
+ len = (op >> 1) as i8;
+ run = (op & 1) != 0;
+ if run {
+ code = br.read_byte()?;
+ }
+ }
+ if run {
+ *el = code;
+ } else {
+ *el = br.read_byte()?;
+ }
+ len -= 1;
+ }
+ }
+ continue;
+ }
+ }
+ let idx = code as usize;
+ let mx = C37_MV[mv_off][idx * 2] as isize;
+ let my = C37_MV[mv_off][idx * 2 + 1] as isize;
+ do_mc(&mut row[col..], &self.pic.frm2, stride,
+ (x as isize) + (col as isize) + mx,
+ (y as isize) + (row_no as isize) * 4 + my,
+ self.pic.width, self.pic.height);
+ len -= 1;
+ }
+ }
+ },
+ 2 => {
+ Self::decode_rle(br, dst, w, h, stride)?;
+ },
+ 3 | 4 => {
+ let has_fills = (flags & 4) != 0;
+ let has_skips = compr == 4;
+ let mut skip_run = 0;
+ for (row_no, row) in dst.chunks_mut(stride * 4).take(h / 4).enumerate() {
+ for col in (0..w).step_by(4) {
+ if skip_run > 0 {
+ for (drow, srow) in row[col..].chunks_mut(stride).zip(prv[col + row_no * 4 * stride..].chunks(stride)) {
+ drow[..4].copy_from_slice(&srow[..4]);
+ }
+ skip_run -= 1;
+ continue;
+ }
+ let opcode = br.read_byte()?;
+ match opcode {
+ 0xFF => {
+ for drow in row[col..].chunks_mut(stride) {
+ br.read_buf(&mut drow[..4])?;
+ }
+ },
+ 0xFE if has_fills => {
+ for drow in row[col..].chunks_mut(stride) {
+ let clr = br.read_byte()?;
+ for el in drow[..4].iter_mut() {
+ *el = clr;
+ }
+ }
+ },
+ 0xFD if has_fills => {
+ let clr = br.read_byte()?;
+ for drow in row[col..].chunks_mut(stride) {
+ for el in drow[..4].iter_mut() {
+ *el = clr;
+ }
+ }
+ },
+ 0 if has_skips => {
+ skip_run = br.read_byte()?;
+ for (drow, srow) in row[col..].chunks_mut(stride).zip(prv[col + row_no * 4 * stride..].chunks(stride)) {
+ drow[..4].copy_from_slice(&srow[..4]);
+ }
+ },
+ _ => {
+ let idx = opcode as usize;
+ let mx = C37_MV[mv_off][idx * 2] as isize;
+ let my = C37_MV[mv_off][idx * 2 + 1] as isize;
+ do_mc(&mut row[col..], &self.pic.frm2, stride,
+ (x as isize) + (col as isize) + mx,
+ (y as isize) + (row_no as isize) * 4 + my,
+ self.pic.width, self.pic.height);
+ },
+ };
+ }
+ }
+ },
+ _ => return Err(DecoderError::InvalidData),
+ };
+
+ Ok(())
+ }
+ fn decode_47(&mut self, br: &mut ByteReader, x: i16, y: i16, w: usize, h: usize) -> DecoderResult<()> {
+ let seq = br.read_u16le()?;
+ let compr = br.read_byte()?;
+ let reorder = br.read_byte()?;
+ let flags = br.read_byte()?;
+ br.read_skip(3)?;
+ let mut clr = [0; 6];
+ br.read_buf(&mut clr)?;
+ let _dec_size = br.read_u32le()?;
+ br.read_skip(4)?;
+ br.read_skip(4)?;
+
+ if (flags & 1) != 0 {
+ for i in 0..256 {
+ for j in i..256 {
+ let val = br.read_byte()?;
+ self.filter[i][j] = val;
+ self.filter[j][i] = val;
+ }
+ }
+ }
+
+ if compr == 2 && !self.glyphs.glyph8_init {
+ self.glyphs.make_glyphs_47();
+ }
+
+ if seq == 0 {
+ for el in self.pic.frm1.iter_mut() {
+ *el = 0;
+ }
+ for el in self.pic.frm2.iter_mut() {
+ *el = 0;
+ }
+ }
+
+ validate!(x >= 0 && y >= 0);
+ let x = x as usize;
+ let y = y as usize;
+ validate!((x + w <= self.pic.width) && (y + h <= self.pic.height));
+
+ let stride = self.pic.width;
+ let dst = &mut self.pic.frm0[x + y * stride..];
+ match compr {
+ 0 => {
+ for line in dst.chunks_mut(stride).take(h) {
+ br.read_buf(&mut line[..w])?;
+ }
+ },
+ 1 => {
+ for row in dst.chunks_mut(stride * 2).take((h + 1) / 2) {
+ for col in (0..w).step_by(2) {
+ let pix = br.read_byte()?;
+ row[col] = pix;
+ row[col + 1] = pix;
+ row[col + stride] = pix;
+ row[col + stride + 1] = pix;
+ }
+ }
+ },
+ 2 => {
+ for (row_no, row) in dst.chunks_mut(stride * 8).take((h + 7) / 8).enumerate() {
+ for col in (0..w).step_by(8) {
+ do_block47(br, &mut row[col..], &self.pic.frm1, &self.pic.frm2, col, row_no * 8, stride, 8, &clr, &self.glyphs)?;
+ }
+ }
+ },
+ 3 => {
+ self.pic.frm0.copy_from_slice(&self.pic.frm2);
+ },
+ 4 => {
+ self.pic.frm0.copy_from_slice(&self.pic.frm1);
+ },
+ 5 => {
+ Self::decode_rle(br, dst, w, h, stride)?;
+ },
+ _ => return Err(DecoderError::InvalidData),
+ };
+
+ self.reorder = if seq == 0 || seq == self.prev_seq + 1 { reorder } else { 0 };
+ self.prev_seq = seq;
+
+ Ok(())
+ }
+ fn decode_48(&mut self, br: &mut ByteReader, x: i16, y: i16, mut w: usize, mut h: usize) -> DecoderResult<()> {
+ let compr = br.read_byte()?;
+ let mvsel = br.read_byte()? as usize;
+ validate!(mvsel < 2);
+ let _seq = br.read_u16le()?;
+ let _packed_size = br.read_u32le()?;
+ let _unpacked_size = br.read_u32le()?;
+ let flags = br.read_byte()?;
+ br.read_skip(3)?;
+ if (flags & 8) != 0 {
+ for i in 0..256 {
+ for j in i..256 {
+ let val = br.read_byte()?;
+ self.filter[i][j] = val;
+ self.filter[j][i] = val;
+ }
+ }
+ }
+
+ w = (w + 7) & !7;
+ h = (h + 7) & !7;
+ std::mem::swap(&mut self.pic.frm0, &mut self.pic.frm2);
+
+ validate!(x >= 0 && y >= 0);
+ let x = x as usize;
+ let y = y as usize;
+ validate!((x + w <= self.pic.width) && (y + h <= self.pic.height));
+
+ let stride = self.pic.width;
+ let dst = &mut self.pic.frm0[x + y * stride..];
+ match compr {
+ 0 => {
+ for line in dst.chunks_mut(stride).take(h) {
+ br.read_buf(&mut line[..w])?;
+ }
+ },
+ 2 => {
+ Self::decode_rle(br, dst, w, h, stride)?;
+ },
+ 3 => {
+ let mut block = [0; 16];
+ for (row_no, row) in dst.chunks_mut(stride * 8).take((h + 7) / 8).enumerate() {
+ for col in (0..w).step_by(8) {
+ let op = br.read_byte()?;
+ match op {
+ 0xFF => {
+ let val = br.read_byte()?;
+
+ // it should be interpolated which means reading top pixels...
+ for el in block.iter_mut() {
+ *el = val;
+ }
+ scale2x(&block, &mut row[col..], stride);
+ },
+ 0xFE => {
+ c48_mv!(offset; &mut row[col..], &self.pic.frm2, br, col, row_no * 8, w, stride, 8);
+ },
+ 0xFD => {
+ block[ 5] = br.read_byte()?;
+ block[ 7] = br.read_byte()?;
+ block[13] = br.read_byte()?;
+ block[15] = br.read_byte()?;
+
+ // it should be interpolated which means reading top pixels...
+ block[ 0] = block[ 5];
+ block[ 1] = block[ 5];
+ block[ 4] = block[ 5];
+ block[ 2] = block[ 7];
+ block[ 3] = block[ 7];
+ block[ 6] = block[ 7];
+ block[ 8] = block[13];
+ block[ 9] = block[13];
+ block[12] = block[13];
+ block[10] = block[15];
+ block[11] = block[15];
+ block[14] = block[15];
+ scale2x(&block, &mut row[col..], stride);
+ },
+ 0xFC => {
+ c48_mv!(index; &mut row[col..], &self.pic.frm2, br, col, row_no * 8, stride, 4, mvsel);
+ },
+ 0xFB => {
+ c48_mv!(offset; &mut row[col..], &self.pic.frm2, br, col, row_no * 8, w, stride, 4);
+ },
+ 0xFA => {
+ br.read_buf(&mut block)?;
+ scale2x(&block, &mut row[col..], stride);
+ },
+ 0xF9 => {
+ c48_mv!(index; &mut row[col..], &self.pic.frm2, br, col, row_no * 8, stride, 2, mvsel);
+ },
+ 0xF8 => {
+ c48_mv!(offset; &mut row[col..], &self.pic.frm2, br, col, row_no * 8, w, stride, 2);
+ },
+ 0xF7 => {
+ for line in row[col..].chunks_mut(stride) {
+ br.read_buf(&mut line[..8])?;
+ }
+ },
+ _ => {
+ br.seek(SeekFrom::Current(-1))?;
+ c48_mv!(index; &mut row[col..], &self.pic.frm2, br, col, row_no * 8, stride, 8, mvsel);
+ },
+ };
+ }
+ }
+ },
+ 5 => {
+ for row in dst.chunks_mut(stride * 2).take((h + 1) / 2) {
+ let mut last = br.read_byte()?;
+ row[0] = last;
+ for col in (1..w).step_by(2) {
+ let new = br.read_byte()?;
+ row[col] = self.filter[last as usize][new as usize];
+ row[col + 1] = new;
+ last = new;
+ }
+ }
+ let mut off0 = 0;
+ let mut off1 = stride;
+ let mut off2 = stride * 2;
+ for _ in (1..h).step_by(2) {
+ for i in 0..w {
+ dst[off1 + i] = self.filter[dst[off0 + i] as usize][dst[off2 + i] as usize];
+ }
+ off0 = off2;
+ off1 += stride * 2;
+ off2 += stride * 2;
+ }
+ },
+ _ => return Err(DecoderError::InvalidData),
+ };
+ Ok(())
+ }
+}
+
+impl NADecoder for Smush1Decoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let Some(edata) = info.get_extradata() {
+ validate!(!edata.is_empty() && edata[0] <= 2);
+ self.version = edata[0];
+ }
+ self.pic.init(info)
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let src = pkt.get_buffer();
+ validate!(src.len() > 8);
+
+ let mut mr = MemoryReader::new_read(&src);
+ let mut br = ByteReader::new(&mut mr);
+
+ let mut store = false;
+ while br.left() > 0 {
+ let tag = br.read_tag()?;
+ let size = br.read_u32be()? as usize;
+ validate!((size as i64) <= br.left());
+ match &tag {
+ b"NPAL" => {
+ validate!((size % 3) == 0);
+ br.read_buf(&mut self.pic.pal[..size])?;
+ },
+ b"XPAL" => {
+ let cmd = br.read_u32be()?;
+ match cmd {
+ 0 => {
+ validate!(size == 0x604);
+ for el in self.pic.pdelta.iter_mut() {
+ *el = br.read_u16le()?;
+ }
+ for (dst, &src) in self.pic.fpal.iter_mut().zip(self.pic.pal.iter()) {
+ *dst = u16::from(src) << 7;
+ }
+ },
+ 1 => {
+ validate!(size == 4 || size == 6);
+ for i in 0..768 {
+ self.pic.fpal[i] = self.pic.fpal[i].wrapping_add(self.pic.pdelta[i]);
+ self.pic.pal[i] = (self.pic.fpal[i] >> 7) as u8;
+ }
+ br.read_skip((size as usize) - 4)?;
+ },
+ 2 => {
+ validate!(size == 0x904);
+ for el in self.pic.pdelta.iter_mut() {
+ *el = br.read_u16le()?;
+ }
+ br.read_buf(&mut self.pic.pal)?;
+ },
+ _ => return Err(DecoderError::InvalidData),
+ };
+ },
+ b"FTCH" => {
+ br.read_skip(size)?;
+ self.pic.frm0.copy_from_slice(&self.pic.frm1);
+ },
+ b"STOR" => {
+ store = true;
+ br.read_skip(size)?;
+ },
+ b"FOBJ" => {
+ validate!(size >= 14);
+ let end = br.tell() + (size as u64);
+ let compression = br.read_byte()?;
+ let cparam = br.read_byte()?;
+ let x = br.read_u16le()? as i16;
+ let y = br.read_u16le()? as i16;
+ let w = br.read_u16le()? as usize;
+ let h = br.read_u16le()? as usize;
+ let _ = br.read_u16le()?;
+ let param2 = br.read_u16le()?;
+
+ match compression {
+ 1 | 3 => self.decode_1(&mut br, x, y, w, h, (compression == 1) ^ (self.version != 1))?,
+ 2 => self.decode_2(&mut br, x, y, w, h, size - 14)?,
+ 4 | 33 => self.decode_4(&mut br, x, y, w, h, cparam, param2)?,
+ 5 | 34 => self.decode_5(&mut br, x, y, w, h, cparam, param2)?,
+ 21 | 44 => self.decode_21(&mut br, x, y, w, h, size - 14)?,
+ 23 => self.decode_23(&mut br, x, y, w, h, cparam, param2, self.version == 1)?,
+ 37 => {
+ let start = br.tell() as usize;
+ let end = start + size - 14;
+ let mut mr = MemoryReader::new_read(&src[start..end]);
+ let mut br = ByteReader::new(&mut mr);
+ self.decode_37(&mut br, x, y, w, h)?;
+ },
+ 47 => {
+ let start = br.tell() as usize;
+ let end = start + size - 14;
+ let mut mr = MemoryReader::new_read(&src[start..end]);
+ let mut br = ByteReader::new(&mut mr);
+ self.decode_47(&mut br, x, y, w, h)?;
+ },
+ 48 => {
+ let start = br.tell() as usize;
+ let end = start + size - 14;
+ let mut mr = MemoryReader::new_read(&src[start..end]);
+ let mut br = ByteReader::new(&mut mr);
+ self.decode_48(&mut br, x, y, w, h)?;
+ },
+ _ => return Err(DecoderError::NotImplemented),
+ };
+ validate!(br.tell() <= end);
+ let tail = end - br.tell();
+ br.read_skip(tail as usize)?;
+ if store {
+ self.pic.frm1.copy_from_slice(&self.pic.frm0);
+ store = false;
+ }
+ },
+ _ => br.read_skip(size)?,
+ };
+ }
+
+ let ret = self.pic.get_frame(pkt);
+
+ if self.reorder == 2 {
+ std::mem::swap(&mut self.pic.frm1, &mut self.pic.frm2);
+ }
+ if self.reorder != 0 {
+ std::mem::swap(&mut self.pic.frm0, &mut self.pic.frm2);
+ }
+ self.reorder = 0;
+
+ ret
+ }
+ fn flush(&mut self) {
+ }
+}
+
+impl NAOptionHandler for Smush1Decoder {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+
+pub fn get_decoder_video_v1() -> Box<dyn NADecoder + Send> {
+ Box::new(Smush1Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::game_register_all_decoders;
+ use crate::game_register_all_demuxers;
+ // samples from Rebel Assault
+ #[test]
+ fn test_smush_anim_v1() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ game_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ game_register_all_decoders(&mut dec_reg);
+
+ test_decoding("smush", "smushv1", "assets/Game/smush/c1block.anm", Some(42), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x39339398, 0x7ce83788, 0xaac917d4, 0xaef9d653]));
+ test_decoding("smush", "smushv1", "assets/Game/smush/c1c3po.anm", Some(42), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x9c1c2422, 0x2121aa7a, 0xc06418bc, 0xd82d704b]));
+ test_decoding("smush", "smushv1", "assets/Game/smush/o1option.anm", Some(4), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x21ea3ee9, 0x3d88bcee, 0x9b71a87a, 0xc5e0a006]));
+ }
+ #[test]
+ fn test_smush_anim_v2() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ game_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ game_register_all_decoders(&mut dec_reg);
+
+ // sample from The Dig
+ test_decoding("smush", "smushv1", "assets/Game/smush/PIGOUT.SAN", Some(42), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x74794559, 0x78a1e484, 0x379a1eec, 0x0609e0b2]));
+ // sample from Full Throttle
+ test_decoding("smush", "smushv1", "assets/Game/smush/FIRE.SAN", Some(16), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x442f73b9, 0x0b98d80f, 0xee2f0e19, 0xa555a33d]));
+ // sample from Mortimer and the Riddles of the Medallion
+ test_decoding("smush", "smushv1", "assets/Game/smush/FOREST1.SAN", Some(24), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xd5b71505, 0x0ffe79dd, 0xc274dbaf, 0x8b952271]));
+ // sample from Curse of Monkey Island
+ test_decoding("smush", "smushv1", "assets/Game/smush/ZAP010.SAN", None, &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x369839f1, 0x2daab242, 0x23995d80, 0x501fbe09]));
+ // sample from Jedi Knight: Mysteries of the Sith
+ test_decoding("smush", "smushv1", "assets/Game/smush/S2L4ECS.SAN", Some(42), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x4525b5f3, 0x9fe5fb23, 0xf5f27980, 0x12589ce1]));
+ }
+}
+
+const C37_MV: [[i8; 255 * 2]; 3] = [
+ [
+ 0, 0, 1, 0, 2, 0, 3, 0, 5, 0, 8, 0, 13, 0, 21,
+ 0, -1, 0, -2, 0, -3, 0, -5, 0, -8, 0, -13, 0, -17, 0,
+ -21, 0, 0, 1, 1, 1, 2, 1, 3, 1, 5, 1, 8, 1, 13,
+ 1, 21, 1, -1, 1, -2, 1, -3, 1, -5, 1, -8, 1, -13, 1,
+ -17, 1, -21, 1, 0, 2, 1, 2, 2, 2, 3, 2, 5, 2, 8,
+ 2, 13, 2, 21, 2, -1, 2, -2, 2, -3, 2, -5, 2, -8, 2,
+ -13, 2, -17, 2, -21, 2, 0, 3, 1, 3, 2, 3, 3, 3, 5,
+ 3, 8, 3, 13, 3, 21, 3, -1, 3, -2, 3, -3, 3, -5, 3,
+ -8, 3, -13, 3, -17, 3, -21, 3, 0, 5, 1, 5, 2, 5, 3,
+ 5, 5, 5, 8, 5, 13, 5, 21, 5, -1, 5, -2, 5, -3, 5,
+ -5, 5, -8, 5, -13, 5, -17, 5, -21, 5, 0, 8, 1, 8, 2,
+ 8, 3, 8, 5, 8, 8, 8, 13, 8, 21, 8, -1, 8, -2, 8,
+ -3, 8, -5, 8, -8, 8, -13, 8, -17, 8, -21, 8, 0, 13, 1,
+ 13, 2, 13, 3, 13, 5, 13, 8, 13, 13, 13, 21, 13, -1, 13,
+ -2, 13, -3, 13, -5, 13, -8, 13, -13, 13, -17, 13, -21, 13, 0,
+ 21, 1, 21, 2, 21, 3, 21, 5, 21, 8, 21, 13, 21, 21, 21,
+ -1, 21, -2, 21, -3, 21, -5, 21, -8, 21, -13, 21, -17, 21, -21,
+ 21, 0, -1, 1, -1, 2, -1, 3, -1, 5, -1, 8, -1, 13, -1,
+ 21, -1, -1, -1, -2, -1, -3, -1, -5, -1, -8, -1, -13, -1, -17,
+ -1, -21, -1, 0, -2, 1, -2, 2, -2, 3, -2, 5, -2, 8, -2,
+ 13, -2, 21, -2, -1, -2, -2, -2, -3, -2, -5, -2, -8, -2, -13,
+ -2, -17, -2, -21, -2, 0, -3, 1, -3, 2, -3, 3, -3, 5, -3,
+ 8, -3, 13, -3, 21, -3, -1, -3, -2, -3, -3, -3, -5, -3, -8,
+ -3, -13, -3, -17, -3, -21, -3, 0, -5, 1, -5, 2, -5, 3, -5,
+ 5, -5, 8, -5, 13, -5, 21, -5, -1, -5, -2, -5, -3, -5, -5,
+ -5, -8, -5, -13, -5, -17, -5, -21, -5, 0, -8, 1, -8, 2, -8,
+ 3, -8, 5, -8, 8, -8, 13, -8, 21, -8, -1, -8, -2, -8, -3,
+ -8, -5, -8, -8, -8, -13, -8, -17, -8, -21, -8, 0, -13, 1, -13,
+ 2, -13, 3, -13, 5, -13, 8, -13, 13, -13, 21, -13, -1, -13, -2,
+ -13, -3, -13, -5, -13, -8, -13, -13, -13, -17, -13, -21, -13, 0, -17,
+ 1, -17, 2, -17, 3, -17, 5, -17, 8, -17, 13, -17, 21, -17, -1,
+ -17, -2, -17, -3, -17, -5, -17, -8, -17, -13, -17, -17, -17, -21, -17,
+ 0, -21, 1, -21, 2, -21, 3, -21, 5, -21, 8, -21, 13, -21, 21,
+ -21, -1, -21, -2, -21, -3, -21, -5, -21, -8, -21, -13, -21, -17, -21
+ ], [
+ 0, 0, -8, -29, 8, -29, -18, -25, 17, -25, 0, -23, -6, -22, 6,
+ -22, -13, -19, 12, -19, 0, -18, 25, -18, -25, -17, -5, -17, 5, -17,
+ -10, -15, 10, -15, 0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8,
+ -11, -2, -11, 0, -11, 2, -11, 8, -11, -15, -10, -4, -10, 4, -10,
+ 15, -10, -6, -9, -1, -9, 1, -9, 6, -9, -29, -8, -11, -8, -8,
+ -8, -3, -8, 3, -8, 8, -8, 11, -8, 29, -8, -5, -7, -2, -7,
+ 0, -7, 2, -7, 5, -7, -22, -6, -9, -6, -6, -6, -3, -6, -1,
+ -6, 1, -6, 3, -6, 6, -6, 9, -6, 22, -6, -17, -5, -7, -5,
+ -4, -5, -2, -5, 0, -5, 2, -5, 4, -5, 7, -5, 17, -5, -13,
+ -4, -10, -4, -5, -4, -3, -4, -1, -4, 0, -4, 1, -4, 3, -4,
+ 5, -4, 10, -4, 13, -4, -8, -3, -6, -3, -4, -3, -3, -3, -2,
+ -3, -1, -3, 0, -3, 1, -3, 2, -3, 4, -3, 6, -3, 8, -3,
+ -11, -2, -7, -2, -5, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1,
+ -2, 2, -2, 3, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1,
+ -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3,
+ -1, 4, -1, 6, -1, 9, -1, -31, 0, -23, 0, -18, 0, -14, 0,
+ -11, 0, -7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0,
+ -31, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
+ 14, 0, 18, 0, 23, 0, 31, 0, -9, 1, -6, 1, -4, 1, -3,
+ 1, -2, 1, -1, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
+ 6, 1, 9, 1, -11, 2, -7, 2, -5, 2, -3, 2, -2, 2, -1,
+ 2, 0, 2, 1, 2, 2, 2, 3, 2, 5, 2, 7, 2, 11, 2,
+ -8, 3, -6, 3, -4, 3, -2, 3, -1, 3, 0, 3, 1, 3, 2,
+ 3, 3, 3, 4, 3, 6, 3, 8, 3, -13, 4, -10, 4, -5, 4,
+ -3, 4, -1, 4, 0, 4, 1, 4, 3, 4, 5, 4, 10, 4, 13,
+ 4, -17, 5, -7, 5, -4, 5, -2, 5, 0, 5, 2, 5, 4, 5,
+ 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6, 1,
+ 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0, 7,
+ 2, 7, 5, 7, -29, 8, -11, 8, -8, 8, -3, 8, 3, 8, 8,
+ 8, 11, 8, 29, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10,
+ -4, 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8,
+ 11, 19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15,
+ -5, 17, 5, 17, 25, 17, -25, 18, 0, 18, -12, 19, 13, 19, -6,
+ 22, 6, 22, 0, 23, -17, 25, 18, 25, -8, 29, 8, 29, 0, 31
+ ], [
+ 0, 0, -6, -22, 6, -22, -13, -19, 12, -19, 0, -18, -5, -17, 5,
+ -17, -10, -15, 10, -15, 0, -14, -4, -13, 4, -13, 19, -13, -19, -12,
+ -8, -11, -2, -11, 0, -11, 2, -11, 8, -11, -15, -10, -4, -10, 4,
+ -10, 15, -10, -6, -9, -1, -9, 1, -9, 6, -9, -11, -8, -8, -8,
+ -3, -8, 0, -8, 3, -8, 8, -8, 11, -8, -5, -7, -2, -7, 0,
+ -7, 2, -7, 5, -7, -22, -6, -9, -6, -6, -6, -3, -6, -1, -6,
+ 1, -6, 3, -6, 6, -6, 9, -6, 22, -6, -17, -5, -7, -5, -4,
+ -5, -2, -5, -1, -5, 0, -5, 1, -5, 2, -5, 4, -5, 7, -5,
+ 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -2, -4, -1, -4, 0,
+ -4, 1, -4, 2, -4, 3, -4, 5, -4, 10, -4, 13, -4, -8, -3,
+ -6, -3, -4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 2,
+ -3, 3, -3, 4, -3, 6, -3, 8, -3, -11, -2, -7, -2, -5, -2,
+ -4, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 3,
+ -2, 4, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, -5, -1,
+ -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3,
+ -1, 4, -1, 5, -1, 6, -1, 9, -1, -23, 0, -18, 0, -14, 0,
+ -11, 0, -7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0,
+ -23, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
+ 14, 0, 18, 0, 23, 0, -9, 1, -6, 1, -5, 1, -4, 1, -3,
+ 1, -2, 1, -1, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
+ 5, 1, 6, 1, 9, 1, -11, 2, -7, 2, -5, 2, -4, 2, -3,
+ 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2,
+ 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, -4, 3, -3, 3, -2,
+ 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 6, 3,
+ 8, 3, -13, 4, -10, 4, -5, 4, -3, 4, -2, 4, -1, 4, 0,
+ 4, 1, 4, 2, 4, 3, 4, 5, 4, 10, 4, 13, 4, -17, 5,
+ -7, 5, -4, 5, -2, 5, -1, 5, 0, 5, 1, 5, 2, 5, 4,
+ 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6,
+ 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0,
+ 7, 2, 7, 5, 7, -11, 8, -8, 8, -3, 8, 0, 8, 3, 8,
+ 8, 8, 11, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, -4,
+ 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11,
+ 19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5,
+ 17, 5, 17, 0, 18, -12, 19, 13, 19, -6, 22, 6, 22, 0, 23
+ ]
+];
+
+const C47_MV: [[[i8; 2]; 255]; 2] = [
+ [
+ [ 0, 0], [ -1, -43], [ 6, -43], [ -9, -42], [ 13, -41],
+ [-16, -40], [ 19, -39], [-23, -36], [ 26, -34], [ -2, -33],
+ [ 4, -33], [-29, -32], [ -9, -32], [ 11, -31], [-16, -29],
+ [ 32, -29], [ 18, -28], [-34, -26], [-22, -25], [ -1, -25],
+ [ 3, -25], [ -7, -24], [ 8, -24], [ 24, -23], [ 36, -23],
+ [-12, -22], [ 13, -21], [-38, -20], [ 0, -20], [-27, -19],
+ [ -4, -19], [ 4, -19], [-17, -18], [ -8, -17], [ 8, -17],
+ [ 18, -17], [ 28, -17], [ 39, -17], [-12, -15], [ 12, -15],
+ [-21, -14], [ -1, -14], [ 1, -14], [-41, -13], [ -5, -13],
+ [ 5, -13], [ 21, -13], [-31, -12], [-15, -11], [ -8, -11],
+ [ 8, -11], [ 15, -11], [ -2, -10], [ 1, -10], [ 31, -10],
+ [-23, -9], [-11, -9], [ -5, -9], [ 4, -9], [ 11, -9],
+ [ 42, -9], [ 6, -8], [ 24, -8], [-18, -7], [ -7, -7],
+ [ -3, -7], [ -1, -7], [ 2, -7], [ 18, -7], [-43, -6],
+ [-13, -6], [ -4, -6], [ 4, -6], [ 8, -6], [-33, -5],
+ [ -9, -5], [ -2, -5], [ 0, -5], [ 2, -5], [ 5, -5],
+ [ 13, -5], [-25, -4], [ -6, -4], [ -3, -4], [ 3, -4],
+ [ 9, -4], [-19, -3], [ -7, -3], [ -4, -3], [ -2, -3],
+ [ -1, -3], [ 0, -3], [ 1, -3], [ 2, -3], [ 4, -3],
+ [ 6, -3], [ 33, -3], [-14, -2], [-10, -2], [ -5, -2],
+ [ -3, -2], [ -2, -2], [ -1, -2], [ 0, -2], [ 1, -2],
+ [ 2, -2], [ 3, -2], [ 5, -2], [ 7, -2], [ 14, -2],
+ [ 19, -2], [ 25, -2], [ 43, -2], [ -7, -1], [ -3, -1],
+ [ -2, -1], [ -1, -1], [ 0, -1], [ 1, -1], [ 2, -1],
+ [ 3, -1], [ 10, -1], [ -5, 0], [ -3, 0], [ -2, 0],
+ [ -1, 0], [ 1, 0], [ 2, 0], [ 3, 0], [ 5, 0],
+ [ 7, 0], [-10, 1], [ -7, 1], [ -3, 1], [ -2, 1],
+ [ -1, 1], [ 0, 1], [ 1, 1], [ 2, 1], [ 3, 1],
+ [-43, 2], [-25, 2], [-19, 2], [-14, 2], [ -5, 2],
+ [ -3, 2], [ -2, 2], [ -1, 2], [ 0, 2], [ 1, 2],
+ [ 2, 2], [ 3, 2], [ 5, 2], [ 7, 2], [ 10, 2],
+ [ 14, 2], [-33, 3], [ -6, 3], [ -4, 3], [ -2, 3],
+ [ -1, 3], [ 0, 3], [ 1, 3], [ 2, 3], [ 4, 3],
+ [ 19, 3], [ -9, 4], [ -3, 4], [ 3, 4], [ 7, 4],
+ [ 25, 4], [-13, 5], [ -5, 5], [ -2, 5], [ 0, 5],
+ [ 2, 5], [ 5, 5], [ 9, 5], [ 33, 5], [ -8, 6],
+ [ -4, 6], [ 4, 6], [ 13, 6], [ 43, 6], [-18, 7],
+ [ -2, 7], [ 0, 7], [ 2, 7], [ 7, 7], [ 18, 7],
+ [-24, 8], [ -6, 8], [-42, 9], [-11, 9], [ -4, 9],
+ [ 5, 9], [ 11, 9], [ 23, 9], [-31, 10], [ -1, 10],
+ [ 2, 10], [-15, 11], [ -8, 11], [ 8, 11], [ 15, 11],
+ [ 31, 12], [-21, 13], [ -5, 13], [ 5, 13], [ 41, 13],
+ [ -1, 14], [ 1, 14], [ 21, 14], [-12, 15], [ 12, 15],
+ [-39, 17], [-28, 17], [-18, 17], [ -8, 17], [ 8, 17],
+ [ 17, 18], [ -4, 19], [ 0, 19], [ 4, 19], [ 27, 19],
+ [ 38, 20], [-13, 21], [ 12, 22], [-36, 23], [-24, 23],
+ [ -8, 24], [ 7, 24], [ -3, 25], [ 1, 25], [ 22, 25],
+ [ 34, 26], [-18, 28], [-32, 29], [ 16, 29], [-11, 31],
+ [ 9, 32], [ 29, 32], [ -4, 33], [ 2, 33], [-26, 34],
+ [ 23, 36], [-19, 39], [ 16, 40], [-13, 41], [ 9, 42],
+ [ -6, 43], [ 1, 43], [ 0, 0], [ 0, 0], [ 0, 0],
+ ], [
+ [ 0, 0], [ 1, 0], [ 2, 0], [ 3, 0], [ 5, 0],
+ [ 8, 0], [ 13, 0], [ 21, 0], [ -1, 0], [ -2, 0],
+ [ -3, 0], [ -5, 0], [ -8, 0], [-13, 0], [-17, 0],
+ [-21, 0], [ 0, 1], [ 1, 1], [ 2, 1], [ 3, 1],
+ [ 5, 1], [ 8, 1], [ 13, 1], [ 21, 1], [ -1, 1],
+ [ -2, 1], [ -3, 1], [ -5, 1], [ -8, 1], [-13, 1],
+ [-17, 1], [-21, 1], [ 0, 2], [ 1, 2], [ 2, 2],
+ [ 3, 2], [ 5, 2], [ 8, 2], [ 13, 2], [ 21, 2],
+ [ -1, 2], [ -2, 2], [ -3, 2], [ -5, 2], [ -8, 2],
+ [-13, 2], [-17, 2], [-21, 2], [ 0, 3], [ 1, 3],
+ [ 2, 3], [ 3, 3], [ 5, 3], [ 8, 3], [ 13, 3],
+ [ 21, 3], [ -1, 3], [ -2, 3], [ -3, 3], [ -5, 3],
+ [ -8, 3], [-13, 3], [-17, 3], [-21, 3], [ 0, 5],
+ [ 1, 5], [ 2, 5], [ 3, 5], [ 5, 5], [ 8, 5],
+ [ 13, 5], [ 21, 5], [ -1, 5], [ -2, 5], [ -3, 5],
+ [ -5, 5], [ -8, 5], [-13, 5], [-17, 5], [-21, 5],
+ [ 0, 8], [ 1, 8], [ 2, 8], [ 3, 8], [ 5, 8],
+ [ 8, 8], [ 13, 8], [ 21, 8], [ -1, 8], [ -2, 8],
+ [ -3, 8], [ -5, 8], [ -8, 8], [-13, 8], [-17, 8],
+ [-21, 8], [ 0, 13], [ 1, 13], [ 2, 13], [ 3, 13],
+ [ 5, 13], [ 8, 13], [ 13, 13], [ 21, 13], [ -1, 13],
+ [ -2, 13], [ -3, 13], [ -5, 13], [ -8, 13], [-13, 13],
+ [-17, 13], [-21, 13], [ 0, 21], [ 1, 21], [ 2, 21],
+ [ 3, 21], [ 5, 21], [ 8, 21], [ 13, 21], [ 21, 21],
+ [ -1, 21], [ -2, 21], [ -3, 21], [ -5, 21], [ -8, 21],
+ [-13, 21], [-17, 21], [-21, 21], [ 0, -1], [ 1, -1],
+ [ 2, -1], [ 3, -1], [ 5, -1], [ 8, -1], [ 13, -1],
+ [ 21, -1], [ -1, -1], [ -2, -1], [ -3, -1], [ -5, -1],
+ [ -8, -1], [-13, -1], [-17, -1], [-21, -1], [ 0, -2],
+ [ 1, -2], [ 2, -2], [ 3, -2], [ 5, -2], [ 8, -2],
+ [ 13, -2], [ 21, -2], [ -1, -2], [ -2, -2], [ -3, -2],
+ [ -5, -2], [ -8, -2], [-13, -2], [-17, -2], [-21, -2],
+ [ 0, -3], [ 1, -3], [ 2, -3], [ 3, -3], [ 5, -3],
+ [ 8, -3], [ 13, -3], [ 21, -3], [ -1, -3], [ -2, -3],
+ [ -3, -3], [ -5, -3], [ -8, -3], [-13, -3], [-17, -3],
+ [-21, -3], [ 0, -5], [ 1, -5], [ 2, -5], [ 3, -5],
+ [ 5, -5], [ 8, -5], [ 13, -5], [ 21, -5], [ -1, -5],
+ [ -2, -5], [ -3, -5], [ -5, -5], [ -8, -5], [-13, -5],
+ [-17, -5], [-21, -5], [ 0, -8], [ 1, -8], [ 2, -8],
+ [ 3, -8], [ 5, -8], [ 8, -8], [ 13, -8], [ 21, -8],
+ [ -1, -8], [ -2, -8], [ -3, -8], [ -5, -8], [ -8, -8],
+ [-13, -8], [-17, -8], [-21, -8], [ 0, -13], [ 1, -13],
+ [ 2, -13], [ 3, -13], [ 5, -13], [ 8, -13], [ 13, -13],
+ [ 21, -13], [ -1, -13], [ -2, -13], [ -3, -13], [ -5, -13],
+ [ -8, -13], [-13, -13], [-17, -13], [-21, -13], [ 0, -17],
+ [ 1, -17], [ 2, -17], [ 3, -17], [ 5, -17], [ 8, -17],
+ [ 13, -17], [ 21, -17], [ -1, -17], [ -2, -17], [ -3, -17],
+ [ -5, -17], [ -8, -17], [-13, -17], [-17, -17], [-21, -17],
+ [ 0, -21], [ 1, -21], [ 2, -21], [ 3, -21], [ 5, -21],
+ [ 8, -21], [ 13, -21], [ 21, -21], [ -1, -21], [ -2, -21],
+ [ -3, -21], [ -5, -21], [ -8, -21], [-13, -21], [-17, -21]
+ ]
+];
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+//use std::str::FromStr;
+
+struct FrameData {
+ info: NACodecInfoRef,
+ width: usize,
+ height: usize,
+ frm0: Vec<u16>,
+ frm1: Vec<u16>,
+ frm2: Vec<u16>,
+}
+
+impl FrameData {
+ fn new() -> Self {
+ Self {
+ info: NACodecInfoRef::default(),
+ width: 0,
+ height: 0,
+ frm0: Vec::new(),
+ frm1: Vec::new(),
+ frm2: Vec::new(),
+ }
+ }
+ fn init(&mut self, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ self.width = vinfo.get_width();
+ self.height = vinfo.get_height();
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, RGB565_FORMAT));
+ self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+ self.frm0.resize(self.width * self.height, 0);
+ self.frm1.resize(self.width * self.height, 0);
+ self.frm2.resize(self.width * self.height, 0);
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn get_frame(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
+ if let Some(ref mut vbuf) = bufinfo.get_vbuf16() {
+ let stride = vbuf.get_stride(0);
+ let data = vbuf.get_data_mut().unwrap();
+ for (dst, src) in data.chunks_mut(stride).zip(self.frm0.chunks(self.width).take(self.height)) {
+ dst[..self.width].copy_from_slice(src);
+ }
+ } else {
+ return Err(DecoderError::Bug);
+ }
+
+ let is_intra = pkt.keyframe;
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(is_intra);
+ frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
+ Ok(frm.into_ref())
+ }
+}
+
+fn decode_rle(br: &mut ByteReader, dst: &mut [u8]) -> DecoderResult<()> {
+ let mut len = 0;
+ let mut clr = 0;
+ let mut run = false;
+
+ for el in dst.iter_mut() {
+ if len == 0 {
+ let op = br.read_byte()?;
+ run = (op & 1) != 0;
+ if run {
+ clr = br.read_byte()?;
+ }
+ len = ((op >> 1) + 1) as usize;
+ }
+ *el = if run { clr } else { br.read_byte()? };
+ len -= 1;
+ }
+ validate!(len == 0);
+
+ Ok(())
+}
+
+struct Smush2Decoder {
+ glyphs4: [[u8; 16]; 256],
+ glyphs8: [[u8; 64]; 256],
+ pic: FrameData,
+ rle_buf: Vec<u8>,
+}
+
+impl Smush2Decoder {
+ fn new() -> Self {
+ let mut glyphs4 = [[0; 16]; 256];
+ let mut glyphs8 = [[0; 64]; 256];
+ super::make_glyphs_47(&mut glyphs4, &mut glyphs8);
+ Self {
+ pic: FrameData::new(),
+ rle_buf: Vec::new(),
+ glyphs4, glyphs8,
+ }
+ }
+}
+
+struct BlockData<'a> {
+ glyphs4: &'a [[u8; 16]; 256],
+ glyphs8: &'a [[u8; 64]; 256],
+ frm1: &'a [u16],
+ frm2: &'a [u16],
+ cb: &'a [u16; 256],
+ clr4: [u16; 4],
+ stride: usize,
+}
+
+fn draw_glyph(dst: &mut [u16], stride: usize, bsize: usize, glyph: &[u8], clr2: [u16; 2]) {
+ for (dst, src) in dst.chunks_mut(stride).zip(glyph.chunks_exact(bsize)) {
+ for (el, &bit) in dst[..bsize].iter_mut().zip(src.iter()) {
+ *el = clr2[bit as usize];
+ }
+ }
+}
+
+fn do_block2(br: &mut ByteReader, dst: &mut [u16], x: usize, y: usize, bsize: usize, bdata: &BlockData) -> DecoderResult<()> {
+ let stride = bdata.stride;
+ let op = br.read_byte()?;
+ match op {
+ 0xFF if bsize > 2 => {
+ let hsize = bsize / 2;
+ do_block2(br, dst, x, y, hsize, bdata)?;
+ do_block2(br, &mut dst[hsize..], x + hsize, y, bsize / 2, bdata)?;
+ do_block2(br, &mut dst[hsize * stride..], x, y + hsize, hsize, bdata)?;
+ do_block2(br, &mut dst[hsize * (stride + 1)..], x + hsize, y + hsize, bsize / 2, bdata)?;
+ },
+ 0xFF => {
+ dst[0] = br.read_u16le()?;
+ dst[1] = br.read_u16le()?;
+ dst[stride] = br.read_u16le()?;
+ dst[stride + 1] = br.read_u16le()?;
+ },
+ 0xFE => {
+ let pix = br.read_u16le()?;
+ for dst in dst.chunks_mut(stride).take(bsize) {
+ for el in dst[..bsize].iter_mut() {
+ *el = pix;
+ }
+ }
+ },
+ 0xFD => {
+ let idx = br.read_byte()? as usize;
+ let pix = bdata.cb[idx];
+ for dst in dst.chunks_mut(stride).take(bsize) {
+ for el in dst[..bsize].iter_mut() {
+ *el = pix;
+ }
+ }
+ },
+ 0xF9..=0xFC => {
+ let pix = bdata.clr4[(op - 0xF9) as usize];
+ for dst in dst.chunks_mut(stride).take(bsize) {
+ for el in dst[..bsize].iter_mut() {
+ *el = pix;
+ }
+ }
+ },
+ 0xF8 if bsize > 2 => {
+ let idx = br.read_byte()? as usize;
+ let mut clr2 = [0; 2];
+ clr2[1] = br.read_u16le()?;
+ clr2[0] = br.read_u16le()?;
+ let glyph: &[u8] = if bsize == 8 { &bdata.glyphs8[idx] } else { &bdata.glyphs4[idx] };
+ draw_glyph(dst, stride, bsize, glyph, clr2);
+ },
+ 0xF8 => {
+ dst[0] = br.read_u16le()?;
+ dst[1] = br.read_u16le()?;
+ dst[stride] = br.read_u16le()?;
+ dst[stride + 1] = br.read_u16le()?;
+ },
+ 0xF7 if bsize > 2 => {
+ let idx = br.read_byte()? as usize;
+ let mut clr2 = [0; 2];
+ clr2[1] = bdata.cb[br.read_byte()? as usize];
+ clr2[0] = bdata.cb[br.read_byte()? as usize];
+ let glyph: &[u8] = if bsize == 8 { &bdata.glyphs8[idx] } else { &bdata.glyphs4[idx] };
+ draw_glyph(dst, stride, bsize, glyph, clr2);
+ },
+ 0xF7 => {
+ dst[0] = bdata.cb[br.read_byte()? as usize];
+ dst[1] = bdata.cb[br.read_byte()? as usize];
+ dst[stride] = bdata.cb[br.read_byte()? as usize];
+ dst[stride + 1] = bdata.cb[br.read_byte()? as usize];
+ },
+ 0xF6 => {
+ let off = x + y * stride;
+ let src = &bdata.frm1[off..];
+ for (dst, src) in dst.chunks_mut(stride).zip(src.chunks(stride)).take(bsize) {
+ dst[..bsize].copy_from_slice(&src[..bsize]);
+ }
+ },
+ 0xF5 => {
+ let off = br.read_u16le()? as i16 as isize;
+ let mx = off % (stride as isize);
+ let my = off / (stride as isize);
+ let off = (x as isize) + mx + ((y as isize) + my) * (stride as isize);
+ validate!(off >= 0);
+ let src = &bdata.frm2[off as usize..];
+ for (dst, src) in dst.chunks_mut(stride).zip(src.chunks(stride)).take(bsize) {
+ let size = dst.len().min(src.len()).min(bsize);
+ dst[..size].copy_from_slice(&src[..size]);
+ }
+ },
+ _ => {
+ let mx = C47_MV[op as usize][0] as isize;
+ let my = C47_MV[op as usize][1] as isize;
+ let off = (x as isize) + mx + ((y as isize) + my) * (stride as isize);
+ let src = &bdata.frm2[off as usize..];
+ for (dst, src) in dst.chunks_mut(stride).zip(src.chunks(stride)).take(bsize) {
+ let size = dst.len().min(src.len()).min(bsize);
+ dst[..size].copy_from_slice(&src[..size]);
+ }
+ },
+ };
+ Ok(())
+}
+
+impl NADecoder for Smush2Decoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ self.pic.init(info)
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let src = pkt.get_buffer();
+ validate!(src.len() > 8);
+
+ let mut mr = MemoryReader::new_read(&src);
+ let mut br = ByteReader::new(&mut mr);
+
+ let mut reorder = 0;
+ while br.left() > 0 {
+ let tag = br.read_tag()?;
+ let size = br.read_u32be()? as usize;
+ let tend = br.tell() + (size as u64);
+ validate!((size as i64) <= br.left());
+ match &tag {
+ b"Bl16" => {
+ validate!(size >= 8);
+ br.read_skip(2)?;
+ let _x = br.read_u16le()? as usize;
+ let _y = br.read_u16le()? as usize;
+ br.read_skip(2)?;
+ validate!(_x <= self.pic.width && _y <= self.pic.height);
+ if size > 8 {
+ let w = br.read_u32le()? as usize;
+ let h = br.read_u32le()? as usize;
+ validate!(w == self.pic.width && h == self.pic.height);
+ let seq = br.read_u16le()?;
+ let compr = br.read_byte()?;
+ reorder = br.read_byte()?;
+ br.read_skip(4)?;
+ let mut clr4 = [0; 4];
+ for el in clr4.iter_mut() {
+ *el = br.read_u16le()?;
+ }
+ let bg_clr = br.read_u16le()?;
+ let _fg_clr = br.read_u16le()?;
+ let _unp_size = br.read_u32le()?;
+ let mut cb = [0; 256];
+ for el in cb.iter_mut() {
+ *el = br.read_u16le()?;
+ }
+ if size > 0x230 {
+ br.read_skip(8)?;
+ }
+ validate!(br.tell() < tend);
+ let start = br.tell() as usize;
+ br.seek(SeekFrom::Start(tend))?;
+ let mut mr = MemoryReader::new_read(&src[start..(tend as usize)]);
+ let mut br = ByteReader::new(&mut mr);
+
+ if seq == 0 {
+ for el in self.pic.frm1.iter_mut() {
+ *el = bg_clr;
+ }
+ for el in self.pic.frm2.iter_mut() {
+ *el = bg_clr;
+ }
+ }
+
+ match compr {
+ 0 => {
+ for row in self.pic.frm0.chunks_mut(self.pic.width).take(h) {
+ for el in row[..w].iter_mut() {
+ *el = br.read_u16le()?;
+ }
+ }
+ },
+ 1 => { unimplemented!(); }, //decode half-res and interpolate
+ 2 => {
+ let bdata = BlockData {
+ glyphs4: &self.glyphs4,
+ glyphs8: &self.glyphs8,
+ frm1: &self.pic.frm1,
+ frm2: &self.pic.frm2,
+ stride: self.pic.width,
+ clr4,
+ cb: &cb,
+ };
+ let dst = &mut self.pic.frm0;
+ let stride = self.pic.width;
+ for (row_no, row) in dst.chunks_mut(stride * 8).take((h + 7) / 8).enumerate() {
+ for col in (0..w).step_by(8) {
+ do_block2(&mut br, &mut row[col..], col, row_no * 8, 8, &bdata)?;
+ }
+ }
+ },
+ 3 => {
+ self.pic.frm0.copy_from_slice(&self.pic.frm2);
+ },
+ 4 => {
+ self.pic.frm0.copy_from_slice(&self.pic.frm1);
+ },
+ 5 => {
+ let size = w * h * 2;
+ self.rle_buf.resize(size, 0);
+ decode_rle(&mut br, &mut self.rle_buf)?;
+ for (drow, srow) in self.pic.frm0.chunks_mut(self.pic.width).zip(self.rle_buf.chunks(w * 2)) {
+ for (dst, src) in drow.iter_mut().zip(srow.chunks_exact(2)) {
+ *dst = read_u16le(src)?;
+ }
+ }
+ },
+ 6 => {
+ for row in self.pic.frm0.chunks_mut(self.pic.width).take(h) {
+ for el in row[..w].iter_mut() {
+ let idx = br.read_byte()? as usize;
+ *el = cb[idx];
+ }
+ }
+ },
+ 7 => { unimplemented!(); }, //decode half-res using codebook indices and interpolate
+ 8 => {
+ let size = w * h;
+ self.rle_buf.resize(size, 0);
+ decode_rle(&mut br, &mut self.rle_buf)?;
+ for (row, src) in self.pic.frm0.chunks_mut(self.pic.width).zip(self.rle_buf.chunks(w)) {
+ for (el, &idx) in row.iter_mut().zip(src.iter()) {
+ *el = cb[idx as usize];
+ }
+ }
+ },
+ _ => return Err(DecoderError::NotImplemented),
+ };
+ }
+ },
+ _ => br.read_skip(size)?,
+ };
+ }
+
+ let ret = self.pic.get_frame(pkt);
+
+ if reorder == 2 {
+ std::mem::swap(&mut self.pic.frm1, &mut self.pic.frm2);
+ }
+ if reorder != 0 {
+ std::mem::swap(&mut self.pic.frm0, &mut self.pic.frm2);
+ }
+
+ ret
+ }
+ fn flush(&mut self) {
+ }
+}
+
+impl NAOptionHandler for Smush2Decoder {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+
+pub fn get_decoder_video_v2() -> Box<dyn NADecoder + Send> {
+ Box::new(Smush2Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::game_register_all_decoders;
+ use crate::game_register_all_demuxers;
+ // sample from Grim Fandango
+ #[test]
+ fn test_smush_sanm() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ game_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ game_register_all_decoders(&mut dec_reg);
+
+ // sample from Grim Fandango
+ test_decoding("smush", "smushv2", "assets/Game/smush/lol.snm", Some(4), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5Frames(vec![
+ [0x408e4dc9, 0x4483d7d8, 0xc9fae314, 0x3bb45ec9],
+ [0x83548952, 0x0b4a6ccb, 0x42609794, 0x59d3c7d4],
+ [0x5349f6ca, 0x56361199, 0x7194439f, 0x90df21b8],
+ [0x0c359bab, 0xed69f862, 0x9c899813, 0x3f6aac2a],
+ [0x58870617, 0x97c5f3a6, 0x1b2c761c, 0x6ec1cd0e]]));
+ }
+}
+
+const C47_MV: [[i8; 2]; 255] = [
+ [ 0, 0], [ -1, -43], [ 6, -43], [ -9, -42], [ 13, -41],
+ [-16, -40], [ 19, -39], [-23, -36], [ 26, -34], [ -2, -33],
+ [ 4, -33], [-29, -32], [ -9, -32], [ 11, -31], [-16, -29],
+ [ 32, -29], [ 18, -28], [-34, -26], [-22, -25], [ -1, -25],
+ [ 3, -25], [ -7, -24], [ 8, -24], [ 24, -23], [ 36, -23],
+ [-12, -22], [ 13, -21], [-38, -20], [ 0, -20], [-27, -19],
+ [ -4, -19], [ 4, -19], [-17, -18], [ -8, -17], [ 8, -17],
+ [ 18, -17], [ 28, -17], [ 39, -17], [-12, -15], [ 12, -15],
+ [-21, -14], [ -1, -14], [ 1, -14], [-41, -13], [ -5, -13],
+ [ 5, -13], [ 21, -13], [-31, -12], [-15, -11], [ -8, -11],
+ [ 8, -11], [ 15, -11], [ -2, -10], [ 1, -10], [ 31, -10],
+ [-23, -9], [-11, -9], [ -5, -9], [ 4, -9], [ 11, -9],
+ [ 42, -9], [ 6, -8], [ 24, -8], [-18, -7], [ -7, -7],
+ [ -3, -7], [ -1, -7], [ 2, -7], [ 18, -7], [-43, -6],
+ [-13, -6], [ -4, -6], [ 4, -6], [ 8, -6], [-33, -5],
+ [ -9, -5], [ -2, -5], [ 0, -5], [ 2, -5], [ 5, -5],
+ [ 13, -5], [-25, -4], [ -6, -4], [ -3, -4], [ 3, -4],
+ [ 9, -4], [-19, -3], [ -7, -3], [ -4, -3], [ -2, -3],
+ [ -1, -3], [ 0, -3], [ 1, -3], [ 2, -3], [ 4, -3],
+ [ 6, -3], [ 33, -3], [-14, -2], [-10, -2], [ -5, -2],
+ [ -3, -2], [ -2, -2], [ -1, -2], [ 0, -2], [ 1, -2],
+ [ 2, -2], [ 3, -2], [ 5, -2], [ 7, -2], [ 14, -2],
+ [ 19, -2], [ 25, -2], [ 43, -2], [ -7, -1], [ -3, -1],
+ [ -2, -1], [ -1, -1], [ 0, -1], [ 1, -1], [ 2, -1],
+ [ 3, -1], [ 10, -1], [ -5, 0], [ -3, 0], [ -2, 0],
+ [ -1, 0], [ 1, 0], [ 2, 0], [ 3, 0], [ 5, 0],
+ [ 7, 0], [-10, 1], [ -7, 1], [ -3, 1], [ -2, 1],
+ [ -1, 1], [ 0, 1], [ 1, 1], [ 2, 1], [ 3, 1],
+ [-43, 2], [-25, 2], [-19, 2], [-14, 2], [ -5, 2],
+ [ -3, 2], [ -2, 2], [ -1, 2], [ 0, 2], [ 1, 2],
+ [ 2, 2], [ 3, 2], [ 5, 2], [ 7, 2], [ 10, 2],
+ [ 14, 2], [-33, 3], [ -6, 3], [ -4, 3], [ -2, 3],
+ [ -1, 3], [ 0, 3], [ 1, 3], [ 2, 3], [ 4, 3],
+ [ 19, 3], [ -9, 4], [ -3, 4], [ 3, 4], [ 7, 4],
+ [ 25, 4], [-13, 5], [ -5, 5], [ -2, 5], [ 0, 5],
+ [ 2, 5], [ 5, 5], [ 9, 5], [ 33, 5], [ -8, 6],
+ [ -4, 6], [ 4, 6], [ 13, 6], [ 43, 6], [-18, 7],
+ [ -2, 7], [ 0, 7], [ 2, 7], [ 7, 7], [ 18, 7],
+ [-24, 8], [ -6, 8], [-42, 9], [-11, 9], [ -4, 9],
+ [ 5, 9], [ 11, 9], [ 23, 9], [-31, 10], [ -1, 10],
+ [ 2, 10], [-15, 11], [ -8, 11], [ 8, 11], [ 15, 11],
+ [ 31, 12], [-21, 13], [ -5, 13], [ 5, 13], [ 41, 13],
+ [ -1, 14], [ 1, 14], [ 21, 14], [-12, 15], [ 12, 15],
+ [-39, 17], [-28, 17], [-18, 17], [ -8, 17], [ 8, 17],
+ [ 17, 18], [ -4, 19], [ 0, 19], [ 4, 19], [ 27, 19],
+ [ 38, 20], [-13, 21], [ 12, 22], [-36, 23], [-24, 23],
+ [ -8, 24], [ 7, 24], [ -3, 25], [ 1, 25], [ 22, 25],
+ [ 34, 26], [-18, 28], [-32, 29], [ 16, 29], [-11, 31],
+ [ 9, 32], [ 29, 32], [ -4, 33], [ 2, 33], [-26, 34],
+ [ 23, 36], [-19, 39], [ 16, 40], [-13, 41], [ 9, 42],
+ [ -6, 43], [ 1, 43], [ 0, 0], [ 0, 0], [ 0, 0],
+];