]>
Commit | Line | Data |
---|---|---|
19336baf KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::compr::deflate::Inflate; | |
3 | ||
4 | #[derive(Default)] | |
5 | struct PicParams { | |
6 | width: usize, | |
7 | height: usize, | |
8 | bw: usize, | |
9 | bh: usize, | |
10 | blk_w: usize, | |
11 | blk_h: usize, | |
12 | bpp: usize, | |
13 | bits: u8, | |
14 | } | |
15 | ||
16 | struct ZMBVDecoder { | |
17 | info: NACodecInfoRef, | |
18 | comp: u8, | |
19 | zbuf: Vec<u8>, | |
20 | frm1: Vec<u8>, | |
21 | frm2: Vec<u8>, | |
22 | pparms: PicParams, | |
23 | pal: [u8; 768], | |
24 | infl: Inflate, | |
25 | } | |
26 | ||
27 | impl ZMBVDecoder { | |
28 | fn new() -> Self { | |
29 | Self { | |
30 | info: NACodecInfo::new_dummy(), | |
31 | comp: 0, | |
32 | zbuf: Vec::new(), | |
33 | frm1: Vec::new(), | |
34 | frm2: Vec::new(), | |
35 | pparms: PicParams::default(), | |
36 | pal: [0; 768], | |
37 | infl: Inflate::new(), | |
38 | } | |
39 | } | |
40 | } | |
41 | ||
42 | fn decode_intra(frm: &mut [u8], pal: &mut [u8; 768], pparms: &PicParams, src: &[u8]) -> DecoderResult<()> { | |
43 | let off = if pparms.bits == 8 { | |
44 | validate!(src.len() > 768); | |
45 | pal.copy_from_slice(&src[..768]); | |
46 | pal.len() | |
47 | } else { 0 }; | |
48 | let src = &src[off..]; | |
49 | let size = pparms.width * pparms.height * pparms.bpp; | |
50 | validate!(src.len() >= size); | |
51 | frm[..size].copy_from_slice(&src[..size]); | |
52 | Ok(()) | |
53 | } | |
54 | ||
55 | fn decode_inter(frm: &mut [u8], prev: &[u8], dpal: bool, pal: &mut [u8; 768], pparms: &PicParams, src: &[u8]) -> DecoderResult<()> { | |
56 | let off = if pparms.bits == 8 && dpal { | |
57 | validate!(src.len() > 768); | |
58 | for (dst, &src) in pal.iter_mut().zip(src.iter()) { | |
59 | *dst ^= src; | |
60 | } | |
61 | pal.len() | |
62 | } else { 0 }; | |
63 | let mv_len = (pparms.blk_w * pparms.blk_h * 2 + 3) & !3; | |
64 | validate!(src.len() >= off + mv_len); | |
65 | let mut mvs = src[off..][..mv_len].chunks_exact(2); | |
66 | let mut src = &src[off + mv_len..]; | |
67 | ||
68 | let mut last_bw = pparms.width % pparms.bw; | |
69 | if last_bw == 0 { | |
70 | last_bw = pparms.bw; | |
71 | } | |
72 | let mut last_bh = pparms.height % pparms.bh; | |
73 | if last_bh == 0 { | |
74 | last_bh = pparms.bh; | |
75 | } | |
76 | ||
77 | let stride = pparms.width * pparms.bpp; | |
78 | let mut off = 0; | |
79 | let mut cur_h = pparms.bh; | |
80 | for y in (0..pparms.height).step_by(pparms.bh) { | |
81 | if y + pparms.bh >= pparms.height { | |
82 | cur_h = last_bh; | |
83 | } | |
84 | let mut cur_w = pparms.bw; | |
85 | let mut block_w = cur_w * pparms.bpp; | |
86 | for x in (0..pparms.width).step_by(pparms.bw) { | |
87 | if x + pparms.bw >= pparms.width { | |
88 | cur_w = last_bw; | |
89 | block_w = cur_w * pparms.bpp; | |
90 | } | |
91 | ||
92 | let mv = mvs.next().unwrap_or(&[0; 2]); | |
93 | let has_delta = (mv[0] & 1) != 0; | |
94 | let mv_x = (mv[0] as i8) >> 1; | |
95 | let mv_y = (mv[1] as i8) >> 1; | |
96 | ||
97 | let xoff = (x as isize) + (mv_x as isize); | |
98 | let yoff = (y as isize) + (mv_y as isize); | |
99 | if xoff >= 0 && (xoff as usize) + cur_w <= pparms.width && yoff >= 0 && (yoff as usize) + cur_h <= pparms.height { | |
100 | let src_off = (xoff as usize) * pparms.bpp + (yoff as usize) * stride; | |
101 | ||
102 | for (dline, sline) in frm[off..].chunks_mut(stride).zip(prev[src_off..].chunks(stride)).take(cur_h) { | |
103 | dline[..block_w].copy_from_slice(&sline[..block_w]); | |
104 | } | |
105 | } else { | |
106 | let mut doff = off; | |
78556b82 | 107 | let mut soff = xoff * (pparms.bpp as isize) + yoff * (stride as isize); |
19336baf KS |
108 | for j in 0..cur_h { |
109 | let cy = yoff + (j as isize); | |
78556b82 | 110 | if cy >= 0 && (cy as usize) < pparms.height { |
19336baf KS |
111 | for i in 0..cur_w { |
112 | let cx = xoff + (i as isize); | |
78556b82 | 113 | if cx >= 0 && (cx as usize) < pparms.width { |
19336baf | 114 | for k in 0..pparms.bpp { |
78556b82 | 115 | frm[doff + i * pparms.bpp + k] = prev[(soff + ((i * pparms.bpp + k) as isize)) as usize] |
19336baf KS |
116 | } |
117 | } else { | |
118 | for k in 0..pparms.bpp { | |
119 | frm[doff + i * pparms.bpp + k] = 0; | |
120 | } | |
121 | } | |
122 | } | |
123 | } else { | |
124 | for p in frm[doff..][..block_w].iter_mut() { | |
125 | *p = 0; | |
126 | } | |
127 | } | |
128 | doff += stride; | |
129 | soff += stride as isize; | |
130 | } | |
131 | } | |
132 | if has_delta { | |
133 | validate!(src.len() >= block_w * cur_h); | |
134 | for (dline, sline) in frm[off..].chunks_mut(stride).zip(src.chunks(block_w)).take(cur_h) { | |
135 | for (dst, &src) in dline[..block_w].iter_mut().zip(sline.iter()) { | |
136 | *dst ^= src; | |
137 | } | |
138 | } | |
139 | src = &src[block_w * cur_h..]; | |
140 | } | |
141 | ||
142 | off += pparms.bw * pparms.bpp; | |
143 | } | |
144 | off -= pparms.bw * pparms.blk_w * pparms.bpp; | |
145 | off += pparms.bh * stride; | |
146 | } | |
147 | ||
148 | Ok(()) | |
149 | } | |
150 | ||
151 | const INTRA_FLAG: u8 = 0x01; | |
152 | const DELTA_PAL: u8 = 0x02; | |
153 | ||
154 | const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3, | |
155 | comp_info: [ | |
156 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }), | |
157 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }), | |
158 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }), | |
159 | None, None], | |
160 | elem_size: 2, be: false, alpha: false, palette: false }; | |
161 | const RGB24_0_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3, | |
162 | comp_info: [ | |
163 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 4 }), | |
164 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 4 }), | |
165 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 4 }), | |
166 | None, None], | |
167 | elem_size: 4, be: false, alpha: false, palette: false }; | |
168 | ||
169 | impl NADecoder for ZMBVDecoder { | |
170 | #[allow(clippy::or_fun_call)] | |
171 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
172 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
173 | self.pparms.width = vinfo.get_width(); | |
174 | self.pparms.height = vinfo.get_height(); | |
175 | self.zbuf = vec![0; (self.pparms.width + 255) * (self.pparms.height + 64) * 4]; | |
176 | self.frm1 = vec![0; self.pparms.width * self.pparms.height * 4]; | |
177 | self.frm2 = vec![0; self.pparms.width * self.pparms.height * 4]; | |
178 | Ok(()) | |
179 | } else { | |
180 | Err(DecoderError::InvalidData) | |
181 | } | |
182 | } | |
183 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
184 | let src = pkt.get_buffer(); | |
185 | if src.is_empty() { return Err(DecoderError::ShortData); } | |
186 | ||
187 | let flags = src[0]; | |
188 | let keyframe = (flags & INTRA_FLAG) != 0; | |
189 | ||
190 | if keyframe { | |
191 | validate!(src.len() > 7); | |
192 | let hi_ver = src[1]; | |
193 | let lo_ver = src[2]; | |
194 | let comp = src[3]; | |
195 | let fmt = src[4]; | |
196 | let bw = src[5]; | |
197 | let bh = src[6]; | |
198 | validate!(hi_ver == 0 && lo_ver == 1); | |
199 | validate!(comp == 0 || comp == 1); | |
200 | validate!(bw > 0 && bh > 0); | |
201 | self.comp = comp; | |
202 | self.pparms.bw = bw as usize; | |
203 | self.pparms.bh = bh as usize; | |
204 | let (bits, fmt) = match fmt { | |
205 | 0 => return Err(DecoderError::NotImplemented), //0, | |
206 | 1 => return Err(DecoderError::NotImplemented), //1, | |
207 | 2 => return Err(DecoderError::NotImplemented), //2, | |
208 | 3 => return Err(DecoderError::NotImplemented), //4, | |
209 | 4 => (8, PAL8_FORMAT), | |
210 | 5 => (15, RGB555_FORMAT), | |
211 | 6 => (16, RGB565_FORMAT), | |
212 | 7 => (24, RGB24_FORMAT), | |
213 | 8 => (32, RGB24_0_FORMAT), | |
214 | _ => return Err(DecoderError::NotImplemented), | |
215 | }; | |
216 | self.pparms.blk_w = (self.pparms.width + self.pparms.bw - 1) / self.pparms.bw; | |
217 | self.pparms.blk_h = (self.pparms.height + self.pparms.bh - 1) / self.pparms.bh; | |
218 | if self.pparms.bits != bits { | |
219 | self.pparms.bits = bits; | |
220 | self.pparms.bpp = ((bits + 7) / 8) as usize; | |
221 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.pparms.width, self.pparms.height, false, fmt)); | |
222 | self.info = NACodecInfo::new_ref(self.info.get_name(), myinfo, self.info.get_extradata()).into_ref(); | |
223 | } | |
224 | self.infl.reset(); | |
225 | } else if self.pparms.bits == 0 { | |
226 | return Err(DecoderError::MissingReference); | |
227 | } | |
228 | ||
229 | let off = if keyframe { 7 } else { 1 }; | |
230 | let src = match self.comp { | |
231 | 0 => &src[off..], | |
232 | 1 => { | |
233 | let ret = self.infl.decompress_block(&src[off..], &mut self.zbuf); | |
234 | if ret.is_err() { | |
235 | return Err(DecoderError::InvalidData); | |
236 | } | |
237 | let len = ret.unwrap(); | |
238 | &self.zbuf[..len] | |
239 | }, | |
240 | _ => unreachable!(), | |
241 | }; | |
242 | if keyframe { | |
243 | decode_intra(&mut self.frm1, &mut self.pal, &self.pparms, src)?; | |
244 | } else { | |
245 | decode_inter(&mut self.frm1, &self.frm2, (flags & DELTA_PAL) != 0, &mut self.pal, &self.pparms, src)?; | |
246 | } | |
247 | ||
248 | let vinfo = self.info.get_properties().get_video_info().unwrap(); | |
249 | let mut bufinfo = alloc_video_buffer(vinfo, 0)?; | |
250 | match (self.pparms.bits, &mut bufinfo) { | |
251 | (8, NABufferType::Video(ref mut buf)) => { | |
252 | let stride = buf.get_stride(0); | |
253 | let offset = buf.get_offset(0); | |
254 | let paloff = buf.get_offset(1); | |
255 | let data = buf.get_data_mut().unwrap(); | |
256 | data[paloff..][..768].copy_from_slice(&self.pal); | |
257 | for (dline, sline) in data[offset..].chunks_mut(stride).zip(self.frm1.chunks_exact(self.pparms.width)).take(self.pparms.height) { | |
258 | dline[..self.pparms.width].copy_from_slice(sline); | |
259 | } | |
260 | }, | |
261 | (_, NABufferType::Video16(ref mut buf)) => { | |
262 | let stride = buf.get_stride(0); | |
263 | let offset = buf.get_offset(0); | |
264 | let data = buf.get_data_mut().unwrap(); | |
265 | for (dline, sline) in data[offset..].chunks_mut(stride).zip(self.frm1.chunks_exact(self.pparms.width * 2)).take(self.pparms.height) { | |
266 | for (dst, src) in dline[..self.pparms.width].iter_mut().zip(sline.chunks_exact(2)) { | |
267 | *dst = u16::from(src[0]) | (u16::from(src[1]) << 8); | |
268 | } | |
269 | } | |
270 | }, | |
271 | (24, NABufferType::VideoPacked(ref mut buf)) => { | |
272 | let stride = buf.get_stride(0); | |
273 | let offset = buf.get_offset(0); | |
274 | let data = buf.get_data_mut().unwrap(); | |
275 | for (dline, sline) in data[offset..].chunks_mut(stride).zip(self.frm1.chunks_exact(self.pparms.width * 3)).take(self.pparms.height) { | |
276 | dline[..self.pparms.width * 3].copy_from_slice(sline); | |
277 | } | |
278 | }, | |
279 | (32, NABufferType::VideoPacked(ref mut buf)) => { | |
280 | let stride = buf.get_stride(0); | |
281 | let offset = buf.get_offset(0); | |
282 | let data = buf.get_data_mut().unwrap(); | |
283 | for (dline, sline) in data[offset..].chunks_mut(stride).zip(self.frm1.chunks_exact(self.pparms.width * 4)).take(self.pparms.height) { | |
284 | dline[..self.pparms.width * 4].copy_from_slice(sline); | |
285 | } | |
286 | }, | |
287 | _ => return Err(DecoderError::Bug), | |
288 | }; | |
289 | ||
290 | std::mem::swap(&mut self.frm1, &mut self.frm2); | |
291 | ||
292 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
293 | frm.set_keyframe(keyframe); | |
294 | if keyframe { | |
295 | frm.set_frame_type(FrameType::I); | |
296 | } else { | |
297 | frm.set_frame_type(FrameType::P); | |
298 | } | |
299 | Ok(frm.into_ref()) | |
300 | } | |
301 | fn flush(&mut self) { | |
302 | self.pparms.bits = 0; | |
303 | } | |
304 | } | |
305 | ||
306 | impl NAOptionHandler for ZMBVDecoder { | |
307 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
308 | fn set_options(&mut self, _options: &[NAOption]) { } | |
309 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
310 | } | |
311 | ||
312 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
313 | Box::new(ZMBVDecoder::new()) | |
314 | } | |
315 | ||
316 | #[cfg(test)] | |
317 | mod test { | |
318 | use nihav_core::codecs::RegisteredDecoders; | |
319 | use nihav_core::demuxers::RegisteredDemuxers; | |
320 | use nihav_codec_support::test::dec_video::*; | |
321 | use crate::generic_register_all_decoders; | |
322 | use crate::generic_register_all_demuxers; | |
886cde48 | 323 | // samples are from https://samples.mplayerhq.hu/V-codecs/ZMBV/ |
19336baf KS |
324 | #[test] |
325 | fn test_zmbv_8() { | |
326 | let mut dmx_reg = RegisteredDemuxers::new(); | |
327 | generic_register_all_demuxers(&mut dmx_reg); | |
328 | let mut dec_reg = RegisteredDecoders::new(); | |
329 | generic_register_all_decoders(&mut dec_reg); | |
330 | test_decoding("avi", "zmbv", "assets/Misc/td3_000.avi", Some(10), | |
78556b82 | 331 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5([0x83c57ac3, 0xda325d18, 0x806bd3be, 0x4b108732])); |
19336baf KS |
332 | } |
333 | #[test] | |
334 | fn test_zmbv_15() { | |
335 | let mut dmx_reg = RegisteredDemuxers::new(); | |
336 | generic_register_all_demuxers(&mut dmx_reg); | |
337 | let mut dec_reg = RegisteredDecoders::new(); | |
338 | generic_register_all_decoders(&mut dec_reg); | |
339 | test_decoding("avi", "zmbv", "assets/Misc/zmbv_15bit.avi", Some(20), | |
340 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5([0x9c9d3544, 0x11b437b6, 0x97a47a98, 0xeafb8ec9])); | |
341 | } | |
342 | #[test] | |
343 | fn test_zmbv_16() { | |
344 | let mut dmx_reg = RegisteredDemuxers::new(); | |
345 | generic_register_all_demuxers(&mut dmx_reg); | |
346 | let mut dec_reg = RegisteredDecoders::new(); | |
347 | generic_register_all_decoders(&mut dec_reg); | |
348 | test_decoding("avi", "zmbv", "assets/Misc/zmbv_16bit.avi", Some(20), | |
349 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5([0x5c09564e, 0x000a07c7, 0xf0d8a0d4, 0xa4ef77e6])); | |
350 | } | |
351 | #[test] | |
352 | fn test_zmbv_32() { | |
353 | let mut dmx_reg = RegisteredDemuxers::new(); | |
354 | generic_register_all_demuxers(&mut dmx_reg); | |
355 | let mut dec_reg = RegisteredDecoders::new(); | |
356 | generic_register_all_decoders(&mut dec_reg); | |
357 | test_decoding("avi", "zmbv", "assets/Misc/zmbv_32bit.avi", Some(20), | |
358 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5([0x4ee7b80b, 0xdba2253c, 0x39721ddf, 0x46ed6d53])); | |
359 | } | |
360 | } |