]>
Commit | Line | Data |
---|---|---|
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 | } |