]>
Commit | Line | Data |
---|---|---|
423005dc KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
3 | use nihav_codec_support::codecs::HAMShuffler; | |
4 | ||
5 | #[derive(Default)] | |
6 | struct RleDecoder { | |
7 | info: NACodecInfoRef, | |
8d7a1c5c | 8 | hams: HAMShuffler<u8>, |
423005dc KS |
9 | width: usize, |
10 | height: usize, | |
11 | is_4bit: bool, | |
12 | } | |
13 | ||
14 | impl RleDecoder { | |
15 | fn new() -> Self { | |
16 | Self::default() | |
17 | } | |
18 | fn decode_8bit(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<FrameType> { | |
19 | let mut has_skips = false; | |
20 | ||
21 | if (br.left() as usize) == self.width * self.height { | |
22 | for line in frm.data.chunks_mut(frm.stride[0]).take(self.height) { | |
23 | br.read_buf(&mut line[..self.width])?; | |
24 | } | |
25 | return Ok(FrameType::I); | |
26 | } | |
27 | let mut x = 0; | |
28 | let mut y = 0; | |
29 | let mut doff = 0; | |
30 | loop { | |
31 | let a = br.read_byte()?; | |
32 | let b = br.read_byte()?; | |
33 | if a > 0 { | |
34 | let len = a as usize; | |
35 | validate!(y < self.height); | |
36 | validate!(x + len <= self.width); | |
37 | for _ in 0..len { | |
38 | frm.data[doff] = b; | |
39 | doff += 1; | |
40 | } | |
41 | x += len; | |
42 | } else { | |
43 | match b { | |
44 | 0 => { | |
45 | if x != self.width { | |
46 | has_skips = true; | |
47 | } | |
48 | x = 0; | |
49 | y += 1; | |
50 | }, | |
51 | 1 => { | |
52 | if x != 0 || y != self.height { | |
53 | has_skips = true; | |
54 | } | |
55 | break; | |
56 | }, | |
57 | 2 => { | |
58 | let xoff = br.read_byte()? as usize; | |
59 | let yoff = br.read_byte()? as usize; | |
60 | validate!(x + xoff <= self.width); | |
61 | validate!(y + yoff <= self.height); | |
62 | x += xoff; | |
63 | y += yoff; | |
64 | has_skips = true; | |
65 | }, | |
66 | _ => { | |
67 | let len = b as usize; | |
68 | validate!(y < self.height); | |
69 | validate!(x + len <= self.width); | |
70 | for _ in 0..len { | |
71 | frm.data[doff] = br.read_byte()?; | |
72 | doff += 1; | |
73 | } | |
74 | x += len; | |
75 | if (len & 1) != 0 { | |
76 | br.read_byte()?; // padding | |
77 | } | |
78 | }, | |
79 | }; | |
80 | if b < 3 { | |
81 | doff = x + y * frm.stride[0]; | |
82 | } | |
83 | } | |
84 | } | |
237cc1f9 | 85 | |
423005dc KS |
86 | |
87 | Ok(if has_skips { FrameType::P } else { FrameType::I }) | |
88 | } | |
89 | fn decode_4bit(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<FrameType> { | |
90 | let mut has_skips = false; | |
91 | ||
92 | if (br.left() as usize) == (self.width + 1) / 2 * self.height { | |
93 | for line in frm.data.chunks_mut(frm.stride[0]).take(self.height) { | |
94 | for i in 0..self.width/2 { | |
95 | let clr = br.read_byte()?; | |
96 | line[i * 2] = clr >> 4; | |
97 | line[i * 2 + 1] = clr & 0xF; | |
98 | } | |
99 | if (self.width & 1) == 1 { | |
100 | let clr = br.read_byte()?; | |
101 | line[self.width - 1] = clr >> 4; | |
102 | } | |
103 | } | |
104 | return Ok(FrameType::I); | |
105 | } | |
106 | let mut x = 0; | |
107 | let mut y = 0; | |
108 | let mut doff = 0; | |
109 | loop { | |
110 | let a = br.read_byte()?; | |
111 | let b = br.read_byte()?; | |
112 | if a > 0 { | |
113 | let len = a as usize; | |
114 | validate!(y < self.height); | |
115 | validate!(x + len <= self.width); | |
116 | for _ in 0..len / 2 { | |
117 | frm.data[doff] = b >> 4; | |
118 | doff += 1; | |
119 | frm.data[doff] = b & 0xF; | |
120 | doff += 1; | |
121 | } | |
122 | if (len & 1) != 0 { | |
123 | frm.data[doff] = b >> 4; | |
124 | doff += 1; | |
125 | } | |
126 | x += len; | |
127 | } else { | |
128 | match b { | |
129 | 0 => { | |
130 | if x != self.width { | |
131 | has_skips = true; | |
132 | } | |
133 | x = 0; | |
134 | y += 1; | |
135 | }, | |
136 | 1 => { | |
137 | if x != 0 || y != self.height { | |
138 | has_skips = true; | |
139 | } | |
140 | break; | |
141 | }, | |
142 | 2 => { | |
143 | let xoff = br.read_byte()? as usize; | |
144 | let yoff = br.read_byte()? as usize; | |
145 | validate!(x + xoff <= self.width); | |
146 | validate!(y + yoff <= self.height); | |
147 | x += xoff; | |
148 | y += yoff; | |
149 | has_skips = true; | |
150 | }, | |
151 | _ => { | |
152 | let len = b as usize; | |
153 | validate!(y < self.height); | |
154 | validate!(x + len <= self.width); | |
155 | for _ in 0..len / 2 { | |
156 | let clr = br.read_byte()?; | |
157 | frm.data[doff] = clr >> 4; | |
158 | doff += 1; | |
159 | frm.data[doff] = clr & 0xF; | |
160 | doff += 1; | |
161 | } | |
162 | if (len & 1) != 0 { | |
163 | let clr = br.read_byte()?; | |
164 | frm.data[doff] = clr >> 4; | |
165 | doff += 1; | |
166 | } | |
167 | x += len; | |
168 | if ((len + 1) & 2) != 0 { | |
169 | br.read_byte()?; // padding | |
170 | } | |
171 | }, | |
172 | }; | |
173 | if b < 3 { | |
174 | doff = x + y * frm.stride[0]; | |
175 | } | |
176 | } | |
177 | } | |
423005dc KS |
178 | |
179 | Ok(if has_skips { FrameType::P } else { FrameType::I }) | |
180 | } | |
181 | } | |
182 | ||
183 | impl NADecoder for RleDecoder { | |
184 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
185 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
186 | self.width = vinfo.get_width(); | |
187 | self.height = vinfo.get_height(); | |
188 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, PAL8_FORMAT)); | |
189 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
190 | self.is_4bit = vinfo.bits == 4; | |
191 | ||
192 | Ok(()) | |
193 | } else { | |
194 | Err(DecoderError::InvalidData) | |
195 | } | |
196 | } | |
197 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
198 | let src = pkt.get_buffer(); | |
199 | validate!(src.len() >= 2); | |
200 | let mut mr = MemoryReader::new_read(src.as_slice()); | |
201 | let mut br = ByteReader::new(&mut mr); | |
202 | ||
203 | let ftype; | |
204 | let bufret = self.hams.clone_ref(); | |
205 | let mut buf; | |
206 | if let Some(bbuf) = bufret { | |
207 | buf = bbuf; | |
208 | } else { | |
209 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?; | |
210 | buf = bufinfo.get_vbuf().unwrap(); | |
211 | self.hams.add_frame(buf); | |
212 | buf = self.hams.get_output_frame().unwrap(); | |
213 | } | |
214 | let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); | |
215 | if !self.is_4bit { | |
216 | ftype = self.decode_8bit(&mut br, &mut frm)?; | |
217 | } else { | |
218 | ftype = self.decode_4bit(&mut br, &mut frm)?; | |
219 | } | |
220 | let paloff = frm.offset[1]; | |
221 | let dpal = &mut frm.data[paloff..]; | |
222 | for sd in pkt.side_data.iter() { | |
223 | match *sd { | |
224 | NASideData::Palette(_, ref pal) => { | |
225 | for (dst, src) in dpal.chunks_mut(3).zip(pal.chunks(4)) { | |
226 | dst[0] = src[0]; | |
227 | dst[1] = src[1]; | |
228 | dst[2] = src[2]; | |
229 | } | |
230 | break; | |
231 | }, | |
232 | _ => {}, | |
233 | }; | |
234 | } | |
235 | let buftype = NABufferType::Video(buf); | |
236 | ||
237 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype); | |
238 | frm.set_keyframe(ftype == FrameType::I); | |
239 | frm.set_frame_type(ftype); | |
240 | Ok(frm.into_ref()) | |
241 | } | |
242 | fn flush(&mut self) { | |
243 | self.hams.clear(); | |
244 | } | |
245 | } | |
246 | ||
247 | impl NAOptionHandler for RleDecoder { | |
248 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
249 | fn set_options(&mut self, _options: &[NAOption]) { } | |
250 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
251 | } | |
252 | ||
253 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
254 | Box::new(RleDecoder::new()) | |
255 | } | |
256 | ||
257 | #[cfg(test)] | |
258 | mod test { | |
259 | use nihav_core::codecs::RegisteredDecoders; | |
260 | use nihav_core::demuxers::RegisteredDemuxers; | |
261 | use nihav_codec_support::test::dec_video::*; | |
78fb6560 | 262 | use crate::ms_register_all_decoders; |
423005dc KS |
263 | use nihav_commonfmt::generic_register_all_demuxers; |
264 | #[test] | |
265 | fn test_ms_rle_8bit() { | |
266 | let mut dmx_reg = RegisteredDemuxers::new(); | |
267 | generic_register_all_demuxers(&mut dmx_reg); | |
268 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 269 | ms_register_all_decoders(&mut dec_reg); |
423005dc KS |
270 | |
271 | test_decoding("avi", "msrle", "assets/MS/workcycl-64color.avi", Some(6), &dmx_reg, &dec_reg, | |
272 | ExpectedTestResult::MD5Frames(vec![ | |
273 | [0xdd030d70, 0x0b6140ff, 0xdd01823e, 0x27c18f12], | |
274 | [0xd592aa63, 0x97bafa10, 0x380787ed, 0x71da30c4], | |
275 | [0x78596af1, 0x8c21fa09, 0xd914131b, 0x04e3e176], | |
276 | [0xcfe091d7, 0xccd513d5, 0x5bd3caa3, 0xcc388e4a], | |
277 | [0xbea60252, 0x1e493c7d, 0x9996b50c, 0x8f7a1c24], | |
278 | [0xfab23365, 0xe8070819, 0xa2ce974e, 0x15dcabba], | |
279 | [0xd1cdf200, 0x9c2e6d33, 0xbe3270d1, 0x1dede547]])); | |
280 | } | |
281 | #[test] | |
282 | fn test_ms_rle_8bit_raw() { | |
283 | let mut dmx_reg = RegisteredDemuxers::new(); | |
284 | generic_register_all_demuxers(&mut dmx_reg); | |
285 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 286 | ms_register_all_decoders(&mut dec_reg); |
423005dc KS |
287 | |
288 | test_decoding("avi", "msrle", "assets/MS/suzie_appl_rle8.avi", Some(2), &dmx_reg, &dec_reg, | |
289 | ExpectedTestResult::MD5Frames(vec![ | |
290 | [0xe4d5ad8d, 0x50e8bd7e, 0x0d602ece, 0x3631a8b4], | |
291 | [0x3301ba0e, 0x281c3e54, 0xbd961d44, 0xc352845b], | |
292 | [0x3ed7881d, 0x86acadf7, 0x2922d8bc, 0x8ec9b17e]])); | |
293 | } | |
294 | #[test] | |
295 | fn test_ms_rle_4bit() { | |
296 | let mut dmx_reg = RegisteredDemuxers::new(); | |
297 | generic_register_all_demuxers(&mut dmx_reg); | |
298 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 299 | ms_register_all_decoders(&mut dec_reg); |
423005dc KS |
300 | |
301 | test_decoding("avi", "msrle", "assets/MS/mplayer-msrle-4bit.avi", Some(2), &dmx_reg, &dec_reg, | |
302 | ExpectedTestResult::MD5Frames(vec![ | |
303 | [0x9898c473, 0x80362654, 0xdb40513a, 0xb0c60fd9], | |
304 | [0x281e1531, 0x368a71cb, 0x9dd02f8d, 0xdfe630d9], | |
305 | [0x6faac693, 0x1856d0fd, 0x47933bb2, 0xb2fb02b0]])); | |
306 | } | |
307 | #[test] | |
308 | fn test_ms_rle_4bit_raw() { | |
309 | let mut dmx_reg = RegisteredDemuxers::new(); | |
310 | generic_register_all_demuxers(&mut dmx_reg); | |
311 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 312 | ms_register_all_decoders(&mut dec_reg); |
423005dc KS |
313 | |
314 | test_decoding("avi", "msrle", "assets/MS/suzie_appl_rle4.avi", Some(2), &dmx_reg, &dec_reg, | |
315 | ExpectedTestResult::MD5([0xb5d38296, 0xdae25407, 0x985973f0, 0xb1da9c94])); | |
316 | } | |
317 | } |