| 1 | use nihav_core::codecs::*; |
| 2 | use nihav_core::io::byteio::*; |
| 3 | |
| 4 | const DICT_SIZE: usize = 4096; |
| 5 | const MAX_BITS: u8 = 12; |
| 6 | const INVALID_POS: usize = 65536; |
| 7 | |
| 8 | struct BitReader<'a> { |
| 9 | src: &'a [u8], |
| 10 | pos: usize, |
| 11 | left: u8, |
| 12 | bitbuf: u32, |
| 13 | bits: u8, |
| 14 | } |
| 15 | |
| 16 | impl<'a> BitReader<'a> { |
| 17 | fn new(src: &'a [u8]) -> Self { |
| 18 | Self { |
| 19 | src, |
| 20 | pos: 0, |
| 21 | left: 0, |
| 22 | bitbuf: 0, |
| 23 | bits: 0, |
| 24 | } |
| 25 | } |
| 26 | fn read(&mut self, nbits: u8) -> DecoderResult<u32> { |
| 27 | while self.bits < nbits { |
| 28 | while self.left > 0 && self.bits <= 24 { |
| 29 | self.bitbuf |= u32::from(self.src[self.pos]) << self.bits; |
| 30 | self.bits += 8; |
| 31 | self.pos += 1; |
| 32 | self.left -= 1; |
| 33 | } |
| 34 | if self.bits < nbits { |
| 35 | if self.pos >= self.src.len() { |
| 36 | return Err(DecoderError::ShortData); |
| 37 | } |
| 38 | self.left = self.src[self.pos]; |
| 39 | self.pos += 1; |
| 40 | validate!(self.left > 0); |
| 41 | if self.pos + usize::from(self.left) > self.src.len() { |
| 42 | return Err(DecoderError::ShortData); |
| 43 | } |
| 44 | } |
| 45 | } |
| 46 | let ret = self.bitbuf & ((1 << nbits) - 1); |
| 47 | self.bitbuf >>= nbits; |
| 48 | self.bits -= nbits; |
| 49 | Ok(ret) |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | struct LZWState { |
| 54 | dict_sym: [u8; DICT_SIZE], |
| 55 | dict_prev: [u16; DICT_SIZE], |
| 56 | dict_pos: usize, |
| 57 | dict_lim: usize, |
| 58 | nsyms: usize, |
| 59 | idx_bits: u8, |
| 60 | } |
| 61 | |
| 62 | impl LZWState { |
| 63 | fn new() -> Self { |
| 64 | Self { |
| 65 | dict_sym: [0; DICT_SIZE], |
| 66 | dict_prev: [0; DICT_SIZE], |
| 67 | dict_pos: 0, |
| 68 | dict_lim: 0, |
| 69 | idx_bits: 0, |
| 70 | nsyms: 0, |
| 71 | } |
| 72 | } |
| 73 | fn reset(&mut self, bits: u8) { |
| 74 | self.nsyms = (1 << bits) + 2; |
| 75 | self.dict_pos = self.nsyms; |
| 76 | self.dict_lim = 1 << (bits + 1); |
| 77 | self.idx_bits = bits + 1; |
| 78 | } |
| 79 | fn add(&mut self, prev: usize, sym: u8) { |
| 80 | if self.dict_pos < self.dict_lim { |
| 81 | self.dict_sym [self.dict_pos] = sym; |
| 82 | self.dict_prev[self.dict_pos] = prev as u16; |
| 83 | self.dict_pos += 1; |
| 84 | } |
| 85 | } |
| 86 | fn decode_idx(&self, dst: &mut [u8], pos: usize, idx: usize) -> DecoderResult<usize> { |
| 87 | let mut tot_len = 1; |
| 88 | let mut tidx = idx; |
| 89 | while tidx >= self.nsyms { |
| 90 | tidx = self.dict_prev[tidx] as usize; |
| 91 | tot_len += 1; |
| 92 | } |
| 93 | validate!(pos + tot_len <= dst.len()); |
| 94 | |
| 95 | let mut end = pos + tot_len - 1; |
| 96 | let mut tidx = idx; |
| 97 | while tidx >= self.nsyms { |
| 98 | dst[end] = self.dict_sym[tidx]; |
| 99 | end -= 1; |
| 100 | tidx = self.dict_prev[tidx] as usize; |
| 101 | } |
| 102 | dst[end] = tidx as u8; |
| 103 | |
| 104 | Ok(tot_len) |
| 105 | } |
| 106 | fn unpack(&mut self, src: &[u8], dst: &mut [u8]) -> DecoderResult<()> { |
| 107 | validate!(src.len() >= 4); |
| 108 | let mut br = BitReader::new(&src[1..]); |
| 109 | |
| 110 | let bits = src[0]; |
| 111 | validate!(bits > 0); |
| 112 | let reset_sym = 1 << bits; |
| 113 | let end_sym = reset_sym + 1; |
| 114 | |
| 115 | self.reset(bits); |
| 116 | |
| 117 | let mut pos = 0; |
| 118 | let mut lastidx = INVALID_POS; |
| 119 | loop { |
| 120 | let idx = br.read(self.idx_bits)? as usize; |
| 121 | if idx == reset_sym { |
| 122 | self.reset(bits); |
| 123 | lastidx = INVALID_POS; |
| 124 | continue; |
| 125 | } |
| 126 | if idx == end_sym { |
| 127 | break; |
| 128 | } |
| 129 | validate!(idx <= self.dict_pos); |
| 130 | if idx != self.dict_pos { |
| 131 | let len = self.decode_idx(dst, pos, idx)?; |
| 132 | if lastidx != INVALID_POS { |
| 133 | self.add(lastidx, dst[pos]); |
| 134 | } |
| 135 | pos += len; |
| 136 | } else { |
| 137 | validate!(lastidx != INVALID_POS); |
| 138 | let len = self.decode_idx(dst, pos, lastidx)?; |
| 139 | let lastsym = dst[pos]; |
| 140 | pos += len; |
| 141 | validate!(pos < dst.len()); |
| 142 | dst[pos] = lastsym; |
| 143 | pos += 1; |
| 144 | self.add(lastidx, lastsym); |
| 145 | } |
| 146 | |
| 147 | lastidx = idx; |
| 148 | if self.dict_pos == self.dict_lim && self.idx_bits < MAX_BITS { |
| 149 | self.dict_lim <<= 1; |
| 150 | self.idx_bits += 1; |
| 151 | } |
| 152 | } |
| 153 | validate!(pos == dst.len()); |
| 154 | validate!(br.pos + 2 == src.len()); |
| 155 | Ok(()) |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | struct GIFDecoder { |
| 160 | info: NACodecInfoRef, |
| 161 | gpal: [u8; 768], |
| 162 | lpal: [u8; 768], |
| 163 | frame: Vec<u8>, |
| 164 | dbuf: Vec<u8>, |
| 165 | width: usize, |
| 166 | height: usize, |
| 167 | lzw: LZWState, |
| 168 | transp: Option<u8>, |
| 169 | } |
| 170 | |
| 171 | impl GIFDecoder { |
| 172 | fn new() -> Self { |
| 173 | Self { |
| 174 | info: NACodecInfoRef::default(), |
| 175 | gpal: [0; 768], |
| 176 | lpal: [0; 768], |
| 177 | frame: Vec::new(), |
| 178 | dbuf: Vec::new(), |
| 179 | width: 0, |
| 180 | height: 0, |
| 181 | lzw: LZWState::new(), |
| 182 | transp: None, |
| 183 | } |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | impl NADecoder for GIFDecoder { |
| 188 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 189 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
| 190 | self.width = vinfo.width; |
| 191 | self.height = vinfo.height; |
| 192 | self.transp = None; |
| 193 | self.gpal = [0; 768]; |
| 194 | if let Some(ref edata) = info.get_extradata() { |
| 195 | validate!(edata.len() >= 3); |
| 196 | if edata[1] != 0 { |
| 197 | self.transp = Some(edata[1]); |
| 198 | } |
| 199 | self.gpal[..edata.len() - 3].copy_from_slice(&edata[3..]); |
| 200 | } |
| 201 | self.frame = vec![0; self.width * self.height]; |
| 202 | self.dbuf = vec![0; self.width * self.height]; |
| 203 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, PAL8_FORMAT)); |
| 204 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
| 205 | |
| 206 | Ok(()) |
| 207 | } else { |
| 208 | Err(DecoderError::InvalidData) |
| 209 | } |
| 210 | } |
| 211 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 212 | let src = pkt.get_buffer(); |
| 213 | validate!(src.len() > 0); |
| 214 | |
| 215 | for sd in pkt.side_data.iter() { |
| 216 | if let NASideData::Palette(true, ref pal) = sd { |
| 217 | for (dst, src) in self.gpal.chunks_mut(3).zip(pal.chunks(4)) { |
| 218 | dst[0] = src[0]; |
| 219 | dst[1] = src[1]; |
| 220 | dst[2] = src[2]; |
| 221 | } |
| 222 | break; |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | let mut mr = MemoryReader::new_read(&src); |
| 227 | let mut br = ByteReader::new(&mut mr); |
| 228 | let tag = br.read_byte()?; |
| 229 | validate!(tag == 0x2C); |
| 230 | let left = usize::from(br.read_u16le()?); |
| 231 | let top = usize::from(br.read_u16le()?); |
| 232 | let width = usize::from(br.read_u16le()?); |
| 233 | let height = usize::from(br.read_u16le()?); |
| 234 | validate!(width > 0 && height > 0); |
| 235 | validate!(left + width <= self.width && top + height <= self.height); |
| 236 | let flags = br.read_byte()?; |
| 237 | let local_pal = (flags & 0x80) != 0; |
| 238 | if local_pal { |
| 239 | let csize = 3 << ((flags & 7) + 1); |
| 240 | br.read_buf(&mut self.lpal[..csize])?; |
| 241 | } |
| 242 | |
| 243 | let start = br.tell() as usize; |
| 244 | self.dbuf.resize(width * height, 0); |
| 245 | self.lzw.unpack(&src[start..], &mut self.dbuf)?; |
| 246 | |
| 247 | if let Some(tpix) = self.transp { |
| 248 | for (dline, sline) in self.frame.chunks_exact_mut(self.width).skip(top) |
| 249 | .zip(self.dbuf.chunks_exact(width)) { |
| 250 | for (dst, &src) in dline[left..][..width].iter_mut().zip(sline.iter()) { |
| 251 | if src != tpix { |
| 252 | *dst = src; |
| 253 | } |
| 254 | } |
| 255 | } |
| 256 | } else { |
| 257 | for (dline, sline) in self.frame.chunks_exact_mut(self.width).skip(top) |
| 258 | .zip(self.dbuf.chunks_exact(width)) { |
| 259 | dline[left..][..width].copy_from_slice(sline); |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | let buf = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?; |
| 264 | let mut vbuf = buf.get_vbuf().unwrap(); |
| 265 | let paloff = vbuf.get_offset(1); |
| 266 | let stride = vbuf.get_stride(0); |
| 267 | let data = vbuf.get_data_mut().unwrap(); |
| 268 | |
| 269 | for (drow, srow) in data.chunks_exact_mut(stride).zip(self.frame.chunks_exact(self.width)) { |
| 270 | drow[..self.width].copy_from_slice(srow); |
| 271 | } |
| 272 | data[paloff..][..768].copy_from_slice(if local_pal { &self.lpal } else { &self.gpal }); |
| 273 | |
| 274 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buf); |
| 275 | let ftype = if pkt.keyframe { FrameType::I } else { FrameType::P }; |
| 276 | frm.set_frame_type(ftype); |
| 277 | Ok(frm.into_ref()) |
| 278 | } |
| 279 | fn flush(&mut self) { |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | impl NAOptionHandler for GIFDecoder { |
| 284 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } |
| 285 | fn set_options(&mut self, _options: &[NAOption]) { } |
| 286 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } |
| 287 | } |
| 288 | |
| 289 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
| 290 | Box::new(GIFDecoder::new()) |
| 291 | } |
| 292 | |
| 293 | #[cfg(test)] |
| 294 | mod test { |
| 295 | use nihav_core::codecs::RegisteredDecoders; |
| 296 | use nihav_core::demuxers::RegisteredDemuxers; |
| 297 | use nihav_codec_support::test::dec_video::*; |
| 298 | use crate::*; |
| 299 | |
| 300 | // sample: https://samples.mplayerhq.hu/image-samples/GIF/3D.gif |
| 301 | #[test] |
| 302 | fn test_gif_decoder() { |
| 303 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 304 | generic_register_all_demuxers(&mut dmx_reg); |
| 305 | let mut dec_reg = RegisteredDecoders::new(); |
| 306 | generic_register_all_decoders(&mut dec_reg); |
| 307 | |
| 308 | test_decoding("gif", "gif", "assets/Misc/3D.gif", |
| 309 | Some(2), &dmx_reg, &dec_reg, |
| 310 | ExpectedTestResult::MD5Frames(vec![ |
| 311 | [0x95e68f8f, 0xe899ac86, 0x0af66a0a, 0x34a4a00e], |
| 312 | [0xdf920e8c, 0xeb57c5f8, 0xd862507e, 0xd733fca3], |
| 313 | [0x75bee5cb, 0xefb2076c, 0xfce61f8a, 0x2d2b30df]])); |
| 314 | } |
| 315 | } |