]>
Commit | Line | Data |
---|---|---|
801bba83 KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
b4d5b851 | 3 | use nihav_codec_support::codecs::HAMShuffler; |
801bba83 KS |
4 | |
5 | #[derive(Default)] | |
6 | struct MidividDecoder { | |
7 | info: NACodecInfoRef, | |
8 | hams: HAMShuffler, | |
9 | lzbuf: Vec<u8>, | |
10 | width: usize, | |
11 | height: usize, | |
12 | } | |
13 | ||
14 | impl MidividDecoder { | |
15 | fn new() -> Self { | |
16 | Self::default() | |
17 | } | |
18 | } | |
19 | ||
20 | fn lz_decompress(src: &[u8], dst: &mut [u8]) -> DecoderResult<()> { | |
21 | let mut spos = 0; | |
22 | let mut dpos = 0; | |
23 | let end = src.len(); | |
24 | while spos < end { | |
25 | let oplo = src[spos] as u16; | |
26 | spos += 1; | |
27 | if spos >= end { return Err(DecoderError::ShortData); } | |
28 | let ophi = src[spos] as u16; | |
29 | spos += 1; | |
30 | let mut op = (ophi << 8) | oplo; | |
31 | for _ in 0..16 { | |
32 | if spos >= end { return Ok(()); } | |
33 | let b = src[spos]; | |
34 | spos += 1; | |
35 | ||
36 | if (op & 1) == 0 { | |
37 | validate!(dpos < dst.len()); | |
38 | dst[dpos] = b; | |
39 | dpos += 1; | |
40 | } else { | |
41 | validate!(spos < end); | |
42 | let bb = src[spos]; | |
43 | spos += 1; | |
44 | ||
45 | let offset = (((b as usize) & 0xF0) << 4) | (bb as usize); | |
46 | let copy_len = ((b & 0xF) as usize) + 3; | |
47 | validate!(offset <= dpos); | |
48 | validate!(offset > 0); | |
49 | validate!(dpos + copy_len <= dst.len()); | |
50 | for _ in 0..copy_len { | |
51 | dst[dpos] = dst[dpos - offset]; | |
52 | dpos += 1; | |
53 | } | |
54 | } | |
55 | op >>= 1; | |
56 | } | |
57 | } | |
58 | Ok(()) | |
59 | } | |
60 | ||
61 | fn decode_frame(frm: &mut NASimpleVideoFrame<u8>, src: &[u8], width: usize, height: usize) -> DecoderResult<bool> { | |
62 | validate!(src.len() > 8); | |
63 | let num_vec = read_u16le(&src[0..])? as usize; | |
64 | validate!(num_vec <= 512); | |
65 | let is_intra = read_u16le(&src[2..])? == 1; | |
66 | ||
67 | let (vecs, nblocks, idx_start) = if is_intra { | |
68 | (&src[4..], width / 2 * height / 2, num_vec * 12 + 4) | |
69 | } else { | |
70 | let num_blocks = read_u32le(&src[4..])? as usize; | |
71 | let changeset_size = (width >> 5) * (height >> 2); | |
72 | (&src[8+changeset_size..], num_blocks, num_vec * 12 + 8 + changeset_size) | |
73 | }; | |
74 | validate!(src.len() > idx_start); | |
75 | ||
76 | let src1 = if num_vec > 256 { &src[idx_start + (nblocks + 7)/8..] } else { &src[idx_start..] }; | |
77 | let mut mr = MemoryReader::new_read(src1); | |
78 | let mut idx_br = ByteReader::new(&mut mr); | |
79 | let mut mr = MemoryReader::new_read(&src[idx_start..]); | |
80 | let mut idx9_br = ByteReader::new(&mut mr); | |
81 | let mut hi9 = 0u8; | |
82 | let mut bits = 0u8; | |
83 | for y in (0..height).step_by(2) { | |
84 | for x in (0..width).step_by(2) { | |
85 | if !is_intra { | |
86 | let x4 = x >> 2; | |
87 | let flag_b = src[8 + x4/8 + (y/4) * ((width + 31) >> 5)]; | |
88 | if ((flag_b >> (x4 & 7)) & 1) == 0 { | |
89 | continue; | |
90 | } | |
91 | } | |
92 | let idx = if num_vec <= 256 { | |
93 | idx_br.read_byte()? as usize | |
94 | } else { | |
95 | if bits == 0 { | |
d24468d9 | 96 | hi9 = idx9_br.read_byte()?; |
801bba83 KS |
97 | bits = 8; |
98 | } | |
99 | bits -= 1; | |
100 | let lo = idx_br.read_byte()? as usize; | |
101 | ||
102 | ((((hi9 >> (7 - bits)) & 1) as usize) << 8) | lo | |
103 | }; | |
104 | validate!(idx < num_vec); | |
105 | let vec = &vecs[idx * 12..]; | |
106 | ||
107 | for comp in 0..3 { | |
108 | let dst = &mut frm.data[frm.offset[comp] + x + y * frm.stride[comp]..]; | |
109 | dst[0] = vec[0 + comp]; | |
110 | dst[1] = vec[3 + comp]; | |
111 | dst[frm.stride[comp] + 0] = vec[6 + comp]; | |
112 | dst[frm.stride[comp] + 1] = vec[9 + comp]; | |
113 | } | |
114 | } | |
115 | } | |
d24468d9 | 116 | |
801bba83 KS |
117 | Ok(is_intra) |
118 | } | |
119 | ||
120 | impl NADecoder for MidividDecoder { | |
121 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
122 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
123 | let fmt = NAPixelFormaton::new(ColorModel::YUV(YUVSubmodel::YCbCr), | |
124 | Some(NAPixelChromaton::new(0, 0, false, 8, 0, 0, 1)), | |
125 | Some(NAPixelChromaton::new(0, 0, false, 8, 0, 1, 1)), | |
126 | Some(NAPixelChromaton::new(0, 0, false, 8, 0, 2, 1)), | |
127 | None, None, 0, 3); | |
128 | self.width = vinfo.get_width(); | |
129 | self.height = vinfo.get_height(); | |
130 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, fmt)); | |
131 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
132 | self.lzbuf = vec![0; self.width * self.height * 3]; | |
133 | ||
134 | Ok(()) | |
135 | } else { | |
136 | Err(DecoderError::InvalidData) | |
137 | } | |
138 | } | |
139 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
140 | let src = pkt.get_buffer(); | |
141 | validate!(src.len() > 4); | |
142 | ||
143 | let size = read_u32le(&src[0..])? as usize; | |
144 | validate!(size + 8 == src.len()); | |
145 | let data_ptr; | |
146 | validate!(src.len() > 12); | |
147 | if read_u32le(&src[8..])? == 0 { | |
148 | lz_decompress(&src[12..], self.lzbuf.as_mut_slice())?; | |
149 | data_ptr = self.lzbuf.as_slice(); | |
150 | } else { | |
151 | data_ptr = &src[12..]; | |
152 | } | |
153 | ||
154 | let mut buf; | |
155 | let bufret = self.hams.clone_ref(); | |
156 | if let Some(bbuf) = bufret { | |
157 | buf = bbuf; | |
158 | } else { | |
159 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?; | |
160 | buf = bufinfo.get_vbuf().unwrap(); | |
161 | self.hams.add_frame(buf); | |
162 | buf = self.hams.get_output_frame().unwrap(); | |
163 | } | |
164 | ||
165 | let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); | |
166 | let is_intra = decode_frame(&mut frm, data_ptr, self.width, self.height)?; | |
167 | ||
168 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf)); | |
169 | frm.set_keyframe(is_intra); | |
170 | frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); | |
171 | Ok(frm.into_ref()) | |
172 | } | |
f9be4e75 KS |
173 | fn flush(&mut self) { |
174 | self.hams.clear(); | |
175 | } | |
801bba83 KS |
176 | } |
177 | ||
7d57ae2f KS |
178 | impl NAOptionHandler for MidividDecoder { |
179 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
180 | fn set_options(&mut self, _options: &[NAOption]) { } | |
181 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
182 | } | |
183 | ||
801bba83 | 184 | |
08a1fab7 | 185 | pub fn get_decoder_video() -> Box<dyn NADecoder + Send> { |
801bba83 KS |
186 | Box::new(MidividDecoder::new()) |
187 | } | |
188 | ||
189 | #[cfg(test)] | |
190 | mod test { | |
191 | use nihav_core::codecs::RegisteredDecoders; | |
192 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 193 | use nihav_codec_support::test::dec_video::*; |
e64739f8 KS |
194 | use crate::game_register_all_codecs; |
195 | use nihav_commonfmt::generic_register_all_demuxers; | |
801bba83 KS |
196 | #[test] |
197 | fn test_midivid_video() { | |
198 | let mut dmx_reg = RegisteredDemuxers::new(); | |
199 | generic_register_all_demuxers(&mut dmx_reg); | |
200 | let mut dec_reg = RegisteredDecoders::new(); | |
201 | game_register_all_codecs(&mut dec_reg); | |
202 | ||
bb07b685 KS |
203 | test_decoding("avi", "midivid", "assets/Game/MVDV.avi", Some(16), &dmx_reg, &dec_reg, |
204 | ExpectedTestResult::MD5Frames(vec![ | |
205 | [0x383e1995, 0x32bf000d, 0x2067aa2e, 0x54425bd4], | |
206 | [0x91d0bff6, 0x5106cb75, 0x463ba358, 0xdc17d126], | |
207 | [0x4ce54833, 0xb4fd3e35, 0x639d3830, 0xb47f871b], | |
208 | [0x7c0c5604, 0x3c89e3ff, 0x05ae09f5, 0x7b725143], | |
209 | [0xc561ddd9, 0xa3515c8e, 0x6119b31a, 0xb1608e77], | |
210 | [0xa49bb9aa, 0xaf57e55b, 0xf351d4b0, 0x6289cd91], | |
211 | [0xc7add756, 0x45574231, 0x5f1d651b, 0x2ae29e0d], | |
212 | [0x7dd57d54, 0x4ec83f80, 0xef2e870b, 0x6cc310fe], | |
213 | [0xe9c5fed6, 0xa4a4bab2, 0x70f84ed6, 0xc9d8a010], | |
214 | [0x586ba118, 0x623fd7b9, 0x480fe7ab, 0xa1a5ad6f]])); | |
801bba83 KS |
215 | } |
216 | } |