GIF support
[nihav.git] / nihav-commonfmt / src / codecs / gif.rs
CommitLineData
fc39649d
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3
4const DICT_SIZE: usize = 4096;
5const MAX_BITS: u8 = 12;
6const INVALID_POS: usize = 65536;
7
8struct BitReader<'a> {
9 src: &'a [u8],
10 pos: usize,
11 left: u8,
12 bitbuf: u32,
13 bits: u8,
14}
15
16impl<'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
53struct 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
62impl 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
159struct 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
171impl 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
187impl 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 = tpix;
253 }
254 }
255 dline[left..][..width].copy_from_slice(sline);
256 }
257 } else {
258 for (dline, sline) in self.frame.chunks_exact_mut(self.width).skip(top)
259 .zip(self.dbuf.chunks_exact(width)) {
260 dline[left..][..width].copy_from_slice(sline);
261 }
262 }
263
264 let buf = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
265 let mut vbuf = buf.get_vbuf().unwrap();
266 let paloff = vbuf.get_offset(1);
267 let stride = vbuf.get_stride(0);
268 let data = vbuf.get_data_mut().unwrap();
269
270 for (drow, srow) in data.chunks_exact_mut(stride).zip(self.frame.chunks_exact(self.width)) {
271 drow[..self.width].copy_from_slice(srow);
272 }
273 data[paloff..][..768].copy_from_slice(if local_pal { &self.lpal } else { &self.gpal });
274
275 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buf);
276 let ftype = if pkt.keyframe { FrameType::I } else { FrameType::P };
277 frm.set_frame_type(ftype);
278 Ok(frm.into_ref())
279 }
280 fn flush(&mut self) {
281 }
282}
283
284impl NAOptionHandler for GIFDecoder {
285 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
286 fn set_options(&mut self, _options: &[NAOption]) { }
287 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
288}
289
290pub fn get_decoder() -> Box<dyn NADecoder + Send> {
291 Box::new(GIFDecoder::new())
292}
293
294#[cfg(test)]
295mod test {
296 use nihav_core::codecs::RegisteredDecoders;
297 use nihav_core::demuxers::RegisteredDemuxers;
298 use nihav_codec_support::test::dec_video::*;
299 use crate::*;
300
301 // sample: https://samples.mplayerhq.hu/image-samples/GIF/3D.gif
302 #[test]
303 fn test_gif_decoder() {
304 let mut dmx_reg = RegisteredDemuxers::new();
305 generic_register_all_demuxers(&mut dmx_reg);
306 let mut dec_reg = RegisteredDecoders::new();
307 generic_register_all_decoders(&mut dec_reg);
308
309 test_decoding("gif", "gif", "assets/Misc/3D.gif",
310 Some(2), &dmx_reg, &dec_reg,
311 ExpectedTestResult::MD5Frames(vec![
312 [0x95e68f8f, 0xe899ac86, 0x0af66a0a, 0x34a4a00e],
313 [0xdf920e8c, 0xeb57c5f8, 0xd862507e, 0xd733fca3],
314 [0x75bee5cb, 0xefb2076c, 0xfce61f8a, 0x2d2b30df]]));
315 }
316}