| 1 | use nihav_core::codecs::*; |
| 2 | use nihav_core::io::byteio::*; |
| 3 | use nihav_codec_support::codecs::HAMShuffler; |
| 4 | |
| 5 | struct HAMShuffler16 { |
| 6 | lastframe: Option<NAVideoBufferRef<u16>>, |
| 7 | } |
| 8 | |
| 9 | impl HAMShuffler16 { |
| 10 | fn clear(&mut self) { self.lastframe = None; } |
| 11 | fn add_frame(&mut self, buf: NAVideoBufferRef<u16>) { |
| 12 | self.lastframe = Some(buf); |
| 13 | } |
| 14 | fn clone_ref(&mut self) -> Option<NAVideoBufferRef<u16>> { |
| 15 | if let Some(ref mut frm) = self.lastframe { |
| 16 | let newfrm = frm.copy_buffer(); |
| 17 | *frm = newfrm.clone().into_ref(); |
| 18 | Some(newfrm.into_ref()) |
| 19 | } else { |
| 20 | None |
| 21 | } |
| 22 | } |
| 23 | fn get_output_frame(&mut self) -> Option<NAVideoBufferRef<u16>> { |
| 24 | match self.lastframe { |
| 25 | Some(ref frm) => Some(frm.clone()), |
| 26 | None => None, |
| 27 | } |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | impl Default for HAMShuffler16 { |
| 32 | fn default() -> Self { Self { lastframe: None } } |
| 33 | } |
| 34 | |
| 35 | const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { |
| 36 | model: ColorModel::RGB(RGBSubmodel::RGB), components: 3, |
| 37 | comp_info: [ |
| 38 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }), |
| 39 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }), |
| 40 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }), |
| 41 | None, None], |
| 42 | elem_size: 2, be: false, alpha: false, palette: false }; |
| 43 | |
| 44 | #[derive(Default)] |
| 45 | struct Video1Decoder { |
| 46 | info: NACodecInfoRef, |
| 47 | hams: HAMShuffler, |
| 48 | hams16: HAMShuffler16, |
| 49 | width: usize, |
| 50 | height: usize, |
| 51 | is_16bit: bool, |
| 52 | } |
| 53 | |
| 54 | impl Video1Decoder { |
| 55 | fn new() -> Self { |
| 56 | Self::default() |
| 57 | } |
| 58 | fn decode_frame(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<FrameType> { |
| 59 | let off = frm.offset[0]; |
| 60 | let stride = frm.stride[0]; |
| 61 | let mut skip_count = 0; |
| 62 | let blk_w = (self.width + 3) >> 2; |
| 63 | let blk_h = (self.height + 3) >> 2; |
| 64 | let mut cur_x = 0; |
| 65 | let mut cur_y = 0; |
| 66 | while cur_x < blk_w && cur_y < blk_h { |
| 67 | let op = br.read_u16le()?; |
| 68 | let advance; |
| 69 | if op < 0x8000 { |
| 70 | let mut clr = [0; 2]; |
| 71 | br.read_buf(&mut clr)?; |
| 72 | let mut flags = !op as usize; |
| 73 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; |
| 74 | for j in 0..4 { |
| 75 | for i in 0..4 { |
| 76 | frm.data[cur_off + i + j * stride] = clr[flags & 1]; |
| 77 | flags >>= 1; |
| 78 | } |
| 79 | } |
| 80 | advance = 1; |
| 81 | } else if op < 0x8400 { |
| 82 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; |
| 83 | let clr = op as u8; |
| 84 | for j in 0..4 { |
| 85 | for i in 0..4 { |
| 86 | frm.data[cur_off + i + j * stride] = clr; |
| 87 | } |
| 88 | } |
| 89 | advance = 1; |
| 90 | } else if op < 0x8800 { |
| 91 | advance = (op & 0x3FF) as usize; |
| 92 | validate!(advance > 0); |
| 93 | skip_count += advance; |
| 94 | } else { |
| 95 | let mut clr = [0; 8]; |
| 96 | br.read_buf(&mut clr)?; |
| 97 | let mut flags = !op as usize; |
| 98 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; |
| 99 | for j in 0..4 { |
| 100 | for i in 0..4 { |
| 101 | frm.data[cur_off + i + j * stride] = clr[(i >> 1) * 2 + (j >> 1) * 4 + (flags & 1)]; |
| 102 | flags >>= 1; |
| 103 | } |
| 104 | } |
| 105 | advance = 1; |
| 106 | } |
| 107 | cur_x += advance; |
| 108 | while cur_x >= blk_w { |
| 109 | cur_x -= blk_w; |
| 110 | cur_y += 1; |
| 111 | } |
| 112 | } |
| 113 | validate!(cur_x == 0 && cur_y == blk_h); |
| 114 | if skip_count == 0 { |
| 115 | Ok(FrameType::I) |
| 116 | } else if skip_count < blk_w * blk_h { |
| 117 | Ok(FrameType::P) |
| 118 | } else { |
| 119 | Ok(FrameType::Skip) |
| 120 | } |
| 121 | } |
| 122 | fn decode_frame16(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u16>) -> DecoderResult<FrameType> { |
| 123 | let off = frm.offset[0]; |
| 124 | let stride = frm.stride[0]; |
| 125 | let mut skip_count = 0; |
| 126 | let blk_w = (self.width + 3) >> 2; |
| 127 | let blk_h = (self.height + 3) >> 2; |
| 128 | let mut cur_x = 0; |
| 129 | let mut cur_y = 0; |
| 130 | while cur_x < blk_w && cur_y < blk_h { |
| 131 | let op = br.read_u16le()?; |
| 132 | let advance; |
| 133 | if (op & 0x8000) == 0 { |
| 134 | let mut clr = [0; 8]; |
| 135 | clr[0] = br.read_u16le()?; |
| 136 | clr[1] = br.read_u16le()?; |
| 137 | let mut flags = !op as usize; |
| 138 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; |
| 139 | if (clr[0] & 0x8000) == 0 { |
| 140 | for j in 0..4 { |
| 141 | for i in 0..4 { |
| 142 | frm.data[cur_off + i + j * stride] = clr[flags & 1]; |
| 143 | flags >>= 1; |
| 144 | } |
| 145 | } |
| 146 | } else { |
| 147 | clr[2] = br.read_u16le()?; |
| 148 | clr[3] = br.read_u16le()?; |
| 149 | clr[4] = br.read_u16le()?; |
| 150 | clr[5] = br.read_u16le()?; |
| 151 | clr[6] = br.read_u16le()?; |
| 152 | clr[7] = br.read_u16le()?; |
| 153 | for j in 0..4 { |
| 154 | for i in 0..4 { |
| 155 | frm.data[cur_off + i + j * stride] = clr[(i >> 1) * 2 + (j >> 1) * 4 + (flags & 1)]; |
| 156 | flags >>= 1; |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | advance = 1; |
| 161 | } else if (op & 0xFC00) == 0x8400 { |
| 162 | advance = (op & 0x3FF) as usize; |
| 163 | validate!(advance > 0); |
| 164 | skip_count += advance; |
| 165 | } else { |
| 166 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; |
| 167 | let clr = op & 0x7FFF; |
| 168 | for j in 0..4 { |
| 169 | for i in 0..4 { |
| 170 | frm.data[cur_off + i + j * stride] = clr; |
| 171 | } |
| 172 | } |
| 173 | advance = 1; |
| 174 | } |
| 175 | cur_x += advance; |
| 176 | while cur_x >= blk_w { |
| 177 | cur_x -= blk_w; |
| 178 | cur_y += 1; |
| 179 | } |
| 180 | } |
| 181 | validate!((cur_x == 0 || cur_x == 1) && cur_y == blk_h); |
| 182 | if skip_count == 0 { |
| 183 | Ok(FrameType::I) |
| 184 | } else if skip_count < blk_w * blk_h { |
| 185 | Ok(FrameType::P) |
| 186 | } else { |
| 187 | Ok(FrameType::Skip) |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | impl NADecoder for Video1Decoder { |
| 193 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 194 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
| 195 | self.is_16bit = !vinfo.get_format().palette; |
| 196 | let fmt = if !self.is_16bit { PAL8_FORMAT } else { RGB555_FORMAT }; |
| 197 | self.width = vinfo.get_width(); |
| 198 | self.height = vinfo.get_height(); |
| 199 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, fmt)); |
| 200 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
| 201 | |
| 202 | Ok(()) |
| 203 | } else { |
| 204 | Err(DecoderError::InvalidData) |
| 205 | } |
| 206 | } |
| 207 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 208 | let src = pkt.get_buffer(); |
| 209 | validate!(src.len() >= 2); |
| 210 | let mut mr = MemoryReader::new_read(src.as_slice()); |
| 211 | let mut br = ByteReader::new(&mut mr); |
| 212 | |
| 213 | let buftype; |
| 214 | let ftype; |
| 215 | if !self.is_16bit { |
| 216 | let bufret = self.hams.clone_ref(); |
| 217 | let mut buf; |
| 218 | if let Some(bbuf) = bufret { |
| 219 | buf = bbuf; |
| 220 | } else { |
| 221 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?; |
| 222 | buf = bufinfo.get_vbuf().unwrap(); |
| 223 | self.hams.add_frame(buf); |
| 224 | buf = self.hams.get_output_frame().unwrap(); |
| 225 | } |
| 226 | let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); |
| 227 | ftype = self.decode_frame(&mut br, &mut frm)?; |
| 228 | let paloff = frm.offset[1]; |
| 229 | let dpal = &mut frm.data[paloff..]; |
| 230 | let mut found_pal = false; |
| 231 | for sd in pkt.side_data.iter() { |
| 232 | match *sd { |
| 233 | NASideData::Palette(_, ref pal) => { |
| 234 | for (dst, src) in dpal.chunks_mut(3).zip(pal.chunks(4)) { |
| 235 | dst[0] = src[0]; |
| 236 | dst[1] = src[1]; |
| 237 | dst[2] = src[2]; |
| 238 | } |
| 239 | found_pal = true; |
| 240 | break; |
| 241 | }, |
| 242 | _ => {}, |
| 243 | }; |
| 244 | } |
| 245 | if !found_pal { |
| 246 | for i in 0..256 { |
| 247 | dpal[i * 3 + 0] = i as u8; |
| 248 | dpal[i * 3 + 1] = i as u8; |
| 249 | dpal[i * 3 + 2] = i as u8; |
| 250 | } |
| 251 | } |
| 252 | buftype = NABufferType::Video(buf); |
| 253 | } else { |
| 254 | let bufret = self.hams16.clone_ref(); |
| 255 | let mut buf; |
| 256 | if let Some(bbuf) = bufret { |
| 257 | buf = bbuf; |
| 258 | } else { |
| 259 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?; |
| 260 | buf = bufinfo.get_vbuf16().unwrap(); |
| 261 | self.hams16.add_frame(buf); |
| 262 | buf = self.hams16.get_output_frame().unwrap(); |
| 263 | } |
| 264 | let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); |
| 265 | ftype = self.decode_frame16(&mut br, &mut frm)?; |
| 266 | buftype = NABufferType::Video16(buf); |
| 267 | } |
| 268 | |
| 269 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype); |
| 270 | frm.set_keyframe(ftype == FrameType::I); |
| 271 | frm.set_frame_type(ftype); |
| 272 | Ok(frm.into_ref()) |
| 273 | } |
| 274 | fn flush(&mut self) { |
| 275 | self.hams.clear(); |
| 276 | self.hams16.clear(); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | impl NAOptionHandler for Video1Decoder { |
| 281 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } |
| 282 | fn set_options(&mut self, _options: &[NAOption]) { } |
| 283 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } |
| 284 | } |
| 285 | |
| 286 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
| 287 | Box::new(Video1Decoder::new()) |
| 288 | } |
| 289 | |
| 290 | #[cfg(test)] |
| 291 | mod test { |
| 292 | use nihav_core::codecs::RegisteredDecoders; |
| 293 | use nihav_core::demuxers::RegisteredDemuxers; |
| 294 | use nihav_codec_support::test::dec_video::*; |
| 295 | use crate::ms_register_all_codecs; |
| 296 | use nihav_commonfmt::generic_register_all_demuxers; |
| 297 | #[test] |
| 298 | fn test_ms_video1_8bit() { |
| 299 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 300 | generic_register_all_demuxers(&mut dmx_reg); |
| 301 | let mut dec_reg = RegisteredDecoders::new(); |
| 302 | ms_register_all_codecs(&mut dec_reg); |
| 303 | |
| 304 | test_decoding("avi", "msvideo1", "assets/MS/toon.avi", Some(66), &dmx_reg, &dec_reg, |
| 305 | ExpectedTestResult::MD5([0x0c26ec42, 0xb75bfea7, 0x1e6342ae, 0xb14dcfa3])); |
| 306 | } |
| 307 | #[test] |
| 308 | fn test_ms_video1_16bit() { |
| 309 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 310 | generic_register_all_demuxers(&mut dmx_reg); |
| 311 | let mut dec_reg = RegisteredDecoders::new(); |
| 312 | ms_register_all_codecs(&mut dec_reg); |
| 313 | |
| 314 | test_decoding("avi", "msvideo1", "assets/MS/clock-cram16.avi", None, &dmx_reg, &dec_reg, |
| 315 | ExpectedTestResult::MD5([0x03381fa4, 0x5b294fec, 0xb97a7575, 0xa1a3ffe9])); |
| 316 | } |
| 317 | } |