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