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