| 1 | use nihav_core::codecs::*; |
| 2 | use nihav_core::io::byteio::*; |
| 3 | |
| 4 | #[derive(Default)] |
| 5 | struct MidividDecoder { |
| 6 | info: NACodecInfoRef, |
| 7 | hams: HAMShuffler, |
| 8 | lzbuf: Vec<u8>, |
| 9 | width: usize, |
| 10 | height: usize, |
| 11 | } |
| 12 | |
| 13 | impl MidividDecoder { |
| 14 | fn new() -> Self { |
| 15 | Self::default() |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | fn lz_decompress(src: &[u8], dst: &mut [u8]) -> DecoderResult<()> { |
| 20 | let mut spos = 0; |
| 21 | let mut dpos = 0; |
| 22 | let end = src.len(); |
| 23 | while spos < end { |
| 24 | let oplo = src[spos] as u16; |
| 25 | spos += 1; |
| 26 | if spos >= end { return Err(DecoderError::ShortData); } |
| 27 | let ophi = src[spos] as u16; |
| 28 | spos += 1; |
| 29 | let mut op = (ophi << 8) | oplo; |
| 30 | for _ in 0..16 { |
| 31 | if spos >= end { return Ok(()); } |
| 32 | let b = src[spos]; |
| 33 | spos += 1; |
| 34 | |
| 35 | if (op & 1) == 0 { |
| 36 | validate!(dpos < dst.len()); |
| 37 | dst[dpos] = b; |
| 38 | dpos += 1; |
| 39 | } else { |
| 40 | validate!(spos < end); |
| 41 | let bb = src[spos]; |
| 42 | spos += 1; |
| 43 | |
| 44 | let offset = (((b as usize) & 0xF0) << 4) | (bb as usize); |
| 45 | let copy_len = ((b & 0xF) as usize) + 3; |
| 46 | validate!(offset <= dpos); |
| 47 | validate!(offset > 0); |
| 48 | validate!(dpos + copy_len <= dst.len()); |
| 49 | for _ in 0..copy_len { |
| 50 | dst[dpos] = dst[dpos - offset]; |
| 51 | dpos += 1; |
| 52 | } |
| 53 | } |
| 54 | op >>= 1; |
| 55 | } |
| 56 | } |
| 57 | Ok(()) |
| 58 | } |
| 59 | |
| 60 | fn decode_frame(frm: &mut NASimpleVideoFrame<u8>, src: &[u8], width: usize, height: usize) -> DecoderResult<bool> { |
| 61 | validate!(src.len() > 8); |
| 62 | let num_vec = read_u16le(&src[0..])? as usize; |
| 63 | validate!(num_vec <= 512); |
| 64 | let is_intra = read_u16le(&src[2..])? == 1; |
| 65 | |
| 66 | let (vecs, nblocks, idx_start) = if is_intra { |
| 67 | (&src[4..], width / 2 * height / 2, num_vec * 12 + 4) |
| 68 | } else { |
| 69 | let num_blocks = read_u32le(&src[4..])? as usize; |
| 70 | let changeset_size = (width >> 5) * (height >> 2); |
| 71 | (&src[8+changeset_size..], num_blocks, num_vec * 12 + 8 + changeset_size) |
| 72 | }; |
| 73 | validate!(src.len() > idx_start); |
| 74 | |
| 75 | let src1 = if num_vec > 256 { &src[idx_start + (nblocks + 7)/8..] } else { &src[idx_start..] }; |
| 76 | let mut mr = MemoryReader::new_read(src1); |
| 77 | let mut idx_br = ByteReader::new(&mut mr); |
| 78 | let mut mr = MemoryReader::new_read(&src[idx_start..]); |
| 79 | let mut idx9_br = ByteReader::new(&mut mr); |
| 80 | let mut hi9 = 0u8; |
| 81 | let mut bits = 0u8; |
| 82 | for y in (0..height).step_by(2) { |
| 83 | for x in (0..width).step_by(2) { |
| 84 | if !is_intra { |
| 85 | let x4 = x >> 2; |
| 86 | let flag_b = src[8 + x4/8 + (y/4) * ((width + 31) >> 5)]; |
| 87 | if ((flag_b >> (x4 & 7)) & 1) == 0 { |
| 88 | continue; |
| 89 | } |
| 90 | } |
| 91 | let idx = if num_vec <= 256 { |
| 92 | idx_br.read_byte()? as usize |
| 93 | } else { |
| 94 | if bits == 0 { |
| 95 | hi9 = idx9_br.read_byte()?; |
| 96 | bits = 8; |
| 97 | } |
| 98 | bits -= 1; |
| 99 | let lo = idx_br.read_byte()? as usize; |
| 100 | |
| 101 | ((((hi9 >> (7 - bits)) & 1) as usize) << 8) | lo |
| 102 | }; |
| 103 | validate!(idx < num_vec); |
| 104 | let vec = &vecs[idx * 12..]; |
| 105 | |
| 106 | for comp in 0..3 { |
| 107 | let dst = &mut frm.data[frm.offset[comp] + x + y * frm.stride[comp]..]; |
| 108 | dst[0] = vec[0 + comp]; |
| 109 | dst[1] = vec[3 + comp]; |
| 110 | dst[frm.stride[comp] + 0] = vec[6 + comp]; |
| 111 | dst[frm.stride[comp] + 1] = vec[9 + comp]; |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | Ok(is_intra) |
| 117 | } |
| 118 | |
| 119 | impl NADecoder for MidividDecoder { |
| 120 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 121 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
| 122 | let fmt = NAPixelFormaton::new(ColorModel::YUV(YUVSubmodel::YCbCr), |
| 123 | Some(NAPixelChromaton::new(0, 0, false, 8, 0, 0, 1)), |
| 124 | Some(NAPixelChromaton::new(0, 0, false, 8, 0, 1, 1)), |
| 125 | Some(NAPixelChromaton::new(0, 0, false, 8, 0, 2, 1)), |
| 126 | None, None, 0, 3); |
| 127 | self.width = vinfo.get_width(); |
| 128 | self.height = vinfo.get_height(); |
| 129 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, fmt)); |
| 130 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
| 131 | self.lzbuf = vec![0; self.width * self.height * 3]; |
| 132 | |
| 133 | Ok(()) |
| 134 | } else { |
| 135 | Err(DecoderError::InvalidData) |
| 136 | } |
| 137 | } |
| 138 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 139 | let src = pkt.get_buffer(); |
| 140 | validate!(src.len() > 4); |
| 141 | |
| 142 | let size = read_u32le(&src[0..])? as usize; |
| 143 | validate!(size + 8 == src.len()); |
| 144 | let data_ptr; |
| 145 | validate!(src.len() > 12); |
| 146 | if read_u32le(&src[8..])? == 0 { |
| 147 | lz_decompress(&src[12..], self.lzbuf.as_mut_slice())?; |
| 148 | data_ptr = self.lzbuf.as_slice(); |
| 149 | } else { |
| 150 | data_ptr = &src[12..]; |
| 151 | } |
| 152 | |
| 153 | let mut buf; |
| 154 | let bufret = self.hams.clone_ref(); |
| 155 | if let Some(bbuf) = bufret { |
| 156 | buf = bbuf; |
| 157 | } else { |
| 158 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?; |
| 159 | buf = bufinfo.get_vbuf().unwrap(); |
| 160 | self.hams.add_frame(buf); |
| 161 | buf = self.hams.get_output_frame().unwrap(); |
| 162 | } |
| 163 | |
| 164 | let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); |
| 165 | let is_intra = decode_frame(&mut frm, data_ptr, self.width, self.height)?; |
| 166 | |
| 167 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf)); |
| 168 | frm.set_keyframe(is_intra); |
| 169 | frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); |
| 170 | Ok(frm.into_ref()) |
| 171 | } |
| 172 | fn flush(&mut self) { |
| 173 | self.hams.clear(); |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | |
| 178 | pub fn get_decoder_video() -> Box<dyn NADecoder + Send> { |
| 179 | Box::new(MidividDecoder::new()) |
| 180 | } |
| 181 | |
| 182 | #[cfg(test)] |
| 183 | mod test { |
| 184 | use nihav_core::codecs::RegisteredDecoders; |
| 185 | use nihav_core::demuxers::RegisteredDemuxers; |
| 186 | use nihav_core::test::dec_video::*; |
| 187 | use crate::game_register_all_codecs; |
| 188 | use nihav_commonfmt::generic_register_all_demuxers; |
| 189 | #[test] |
| 190 | fn test_midivid_video() { |
| 191 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 192 | generic_register_all_demuxers(&mut dmx_reg); |
| 193 | let mut dec_reg = RegisteredDecoders::new(); |
| 194 | game_register_all_codecs(&mut dec_reg); |
| 195 | |
| 196 | let file = "assets/Game/MVDV.avi"; |
| 197 | //let file = "assets/Game/bbglogo.avi"; |
| 198 | //let file = "assets/Game/close.avi"; |
| 199 | //let file = "assets/Game/inland.avi"; |
| 200 | //let file = "assets/Game/midway.avi"; |
| 201 | //let file = "assets/Game/midway.1.avi"; |
| 202 | //let file = "assets/Game/open.avi"; |
| 203 | test_file_decoding("avi", file, Some(16), true, false, None, &dmx_reg, &dec_reg); |
| 204 | } |
| 205 | } |