add LinePack decoder
[nihav.git] / nihav-game / src / codecs / arxel_vid.rs
1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use nihav_core::io::bitreader::*;
4 use nihav_codec_support::codecs::HAMShuffler;
5
6 const HEADER_SIZE: usize = 0x2F;
7
8 const MV_2BIT: [(i8, i8); 4] = [(-1, 0), (-1, -1), (1, -1), (0, -2)];
9 const MV_4BIT: [(i8, i8); 16] = [
10 (-2, -3), ( 2, -3), (-1, -4), ( 1, -4),
11 (-1, -2), ( 1, -2), ( 0, -3), ( 0, -4),
12 (-2, 0), (-2, -1), ( 2, -1), (-2, -2),
13 ( 2, -2), (-1, -3), ( 1, -3), ( 0, -5)
14 ];
15
16 const BPP: usize = 4;
17
18 struct ArxelVideoDecoder {
19 info: NACodecInfoRef,
20 tiles: [u8; 65536],
21 version: u8,
22 idx_buf: Vec<usize>,
23 contexts: [[usize; 16]; 4096],
24 ctx_pos: [usize; 4096],
25 hams: HAMShuffler<u8>,
26 }
27
28 impl ArxelVideoDecoder {
29 fn new() -> Self {
30 Self {
31 info: NACodecInfoRef::default(),
32 tiles: [0; 65536],
33 version: 0,
34 idx_buf: Vec::new(),
35 contexts: [[0; 16]; 4096],
36 ctx_pos: [0; 4096],
37 hams: HAMShuffler::new(),
38 }
39 }
40 fn decode_v1(&mut self, src: &[u8]) -> DecoderResult<(NABufferType, bool)> {
41 let mut mr = MemoryReader::new_read(src);
42 let mut br = ByteReader::new(&mut mr);
43
44 let size = br.read_u32le()? as usize;
45 validate!(src.len() >= size + HEADER_SIZE);
46 let part2_off = br.read_u32le()? as u64;
47 validate!(part2_off > 0 && part2_off < (size as u64));
48 let num_tiles = br.read_u16le()? as usize;
49 validate!(num_tiles > 0 && num_tiles < 4096);
50 let tile_size = br.read_u16le()? as usize;
51 let width = br.read_u32le()? as usize;
52 let height = br.read_u32le()? as usize;
53
54 let vinfo = self.info.get_properties().get_video_info().unwrap();
55 validate!(width == vinfo.get_width());
56 validate!(height == vinfo.get_height());
57
58 br.seek(SeekFrom::Start(part2_off + (HEADER_SIZE as u64)))?;
59 let tile_w = if tile_size == 2 { 2 } else { 4 };
60 let tsize = tile_w * BPP;
61
62 match tile_size {
63 2 | 4 => {
64 br.read_buf(&mut self.tiles[..tsize])?;
65 let off = br.tell() as usize;
66 let mut bir = BitReader::new(&src[off..], BitReaderMode::BE);
67 for tile in 1..num_tiles {
68 for i in 0..tsize {
69 self.tiles[tile * tsize + i] = self.tiles[tile * tsize + i - tsize];
70 }
71 let bits = bir.read(3)? as u8 + 1;
72 validate!(bits < 8);
73 for el in self.tiles[tile * tsize..][..tsize].iter_mut() {
74 let mut delta = bir.read(bits)? as i16;
75 if delta != 0 && bir.read_bool()? {
76 delta = -delta;
77 }
78 *el = (i16::from(*el) + delta) as u8;
79 }
80 }
81 },
82 _ => {
83 validate!(tile_size == num_tiles * tsize);
84 br.read_buf(&mut self.tiles[..tile_size])?;
85 },
86 };
87
88 let bufinfo = alloc_video_buffer(vinfo, 0)?;
89 let bufo = bufinfo.get_vbuf();
90 let mut buf = bufo.unwrap();
91 let stride = buf.get_stride(0);
92 let data = buf.get_data_mut().unwrap();
93 let dst = data.as_mut_slice();
94
95 let mut br = BitReader::new(&src[HEADER_SIZE..], BitReaderMode::BE);
96 let idx_bits = if num_tiles < 0x400 { 10 } else if num_tiles < 0x800 { 11 } else { 12 };
97 for y in (0..height).step_by(2) {
98 for x in (0..width).step_by(tile_w) {
99 let dst_pos = x * BPP + y * stride;
100 if !br.read_bool()? {
101 let idx = br.read(idx_bits)? as usize;
102 validate!(idx < num_tiles);
103 dst[dst_pos..][..tsize].copy_from_slice(&self.tiles[idx * tsize..][..tsize]);
104 } else {
105 let (mv_x, mv_y) = if br.read_bool()? {
106 (0, -1)
107 } else if br.read_bool()? {
108 MV_2BIT[br.read(2)? as usize]
109 } else {
110 MV_4BIT[br.read(4)? as usize]
111 };
112
113 let isrc = (dst_pos as isize) + isize::from(mv_x) * (tsize as isize) + isize::from(mv_y) * ((stride * 2) as isize);
114 validate!(isrc >= 0);
115 let src_pos = isrc as usize;
116 validate!(src_pos + tsize <= dst.len());
117 let (src, dst) = dst.split_at_mut(dst_pos);
118 dst[..tsize].copy_from_slice(&src[src_pos..][..tsize]);
119 }
120 }
121 // double lines
122 let lines = &mut dst[y * stride..];
123 let (src, dst) = lines.split_at_mut(stride);
124 dst[..stride].copy_from_slice(src);
125 }
126 Ok((bufinfo, true))
127 }
128 fn add_to_context(&mut self, prev: usize, cur: usize) {
129 self.contexts[prev][self.ctx_pos[prev]] = cur;
130 self.ctx_pos[prev] += 1;
131 if self.ctx_pos[prev] == 16 {
132 self.ctx_pos[prev] = 0;
133 }
134 }
135 fn decode_v2(&mut self, src: &[u8]) -> DecoderResult<(NABufferType, bool)> {
136 let mut mr = MemoryReader::new_read(src);
137 let mut br = ByteReader::new(&mut mr);
138
139 let mut has_tiles = false;
140 let mut is_55 = false;
141 loop {
142 let ftype = br.read_byte()?;
143 match ftype {
144 0x54 => {
145 let size = br.read_u32le()? as usize;
146 let num_tiles = br.read_u16le()? as usize;
147 let tile_size = br.read_u16le()? as usize;
148
149 let tile_w = if tile_size == 2 { 2 } else { 4 };
150 let tsize = tile_w * BPP;
151
152 match tile_size {
153 2 | 4 => {
154 validate!(size >= tsize);
155 br.read_buf(&mut self.tiles[..tsize])?;
156 let off = br.tell() as usize;
157 let mut bir = BitReader::new(&src[off..][..size - tsize], BitReaderMode::LE);
158 for tile in 1..num_tiles {
159 let (prev_tiles, cur_tile) = self.tiles.split_at_mut(tile * tsize);
160 cur_tile[..16].copy_from_slice(&prev_tiles[prev_tiles.len() - 16..]);
161 for comp in 0..BPP {
162 let bits = bir.read(3)? as u8;
163 if bits == 0 {
164 continue;
165 }
166 for i in 0..tile_size {
167 let el = &mut cur_tile[i * BPP + comp];
168 *el = match bits {
169 7 => {
170 bir.read(8)? as u8
171 },
172 _ => {
173 let mut delta = bir.read(bits)? as i16;
174 if delta != 0 && bir.read_bool()? {
175 delta = -delta;
176 }
177 (i16::from(*el) + delta) as u8
178 },
179 };
180 }
181 }
182 }
183 br.read_skip(size - tsize)?;
184 has_tiles = true;
185 },
186 _ => {
187 unimplemented!();
188 },
189 };
190 },
191 0x53 => break,
192 0x55 => {
193 is_55 = true;
194 break;
195 },
196 _ => return Err(DecoderError::InvalidData),
197 };
198 }
199
200 let size = br.read_u32le()? as usize;
201 validate!(size + HEADER_SIZE <= (br.left() as usize) + 4);
202 let part2_off = br.read_u32le()?;
203 validate!(part2_off as usize == size);
204 let num_tiles = br.read_u16le()? as usize;
205 validate!((0..4096).contains(&num_tiles));
206 let tile_size = br.read_u16le()? as usize;
207 let width = br.read_u32le()? as usize;
208 let height = br.read_u32le()? as usize;
209 br.read_skip(0x1B)?;
210
211 let vinfo = self.info.get_properties().get_video_info().unwrap();
212 validate!(width == vinfo.get_width());
213 validate!(height == vinfo.get_height());
214 let is_intra = is_55 && has_tiles;
215
216 let mut vbuf = if is_intra {
217 let binfo = alloc_video_buffer(vinfo, 0)?;
218 let vbuf = binfo.get_vbuf().unwrap();
219 self.hams.add_frame(vbuf);
220 self.hams.get_output_frame().unwrap()
221 } else {
222 if let Some(buf) = self.hams.clone_ref() {
223 buf
224 } else {
225 return Err(DecoderError::MissingReference);
226 }
227 };
228 let stride = vbuf.get_stride(0);
229 let data = vbuf.get_data_mut().unwrap();
230 let dst = data.as_mut_slice();
231
232 let tile_w = if tile_size == 2 { 2 } else { 4 };
233 let tsize = tile_w * BPP;
234 let mut idx_bits = 0;
235 let mut v = num_tiles;
236 while v > 0 {
237 idx_bits += 1;
238 v >>= 1;
239 }
240 let start = br.tell() as usize;
241 let mut br = BitReader::new(&src[start..], BitReaderMode::LE);
242 let mut ypos = 0;
243 let mut last_seen = [0usize.wrapping_sub(1); 4096];
244 let mut cand_list = Vec::with_capacity(4);
245 let istride = width / tile_w;
246 self.idx_buf.resize(istride * height, 0);
247 self.contexts = [[0; 16]; 4096];
248 self.ctx_pos = [0; 4096];
249
250 for y in 0..height {
251 for x8 in (0..istride).step_by(8) {
252 let pos = ypos + x8;
253 if br.read_bool()? {
254 validate!(y > 0);
255 for x in 0..8 {
256 self.idx_buf[pos + x] = self.idx_buf[pos + x - istride];
257 }
258 } else {
259 for x in 0..8 {
260 if br.read_bool()? {
261 validate!(y > 0);
262 self.idx_buf[pos + x] = self.idx_buf[pos + x - istride];
263 } else {
264 let mode = br.read(2)?;
265 match mode {
266 0 => {
267 let idx = br.read(idx_bits)? as usize;
268 self.idx_buf[pos + x] = idx;
269 if y > 0 {
270 self.add_to_context(self.idx_buf[pos + x - istride], idx);
271 }
272 },
273 1 => {
274 cand_list.clear();
275 let cur_pos = pos + x;
276 if y > 0 {
277 last_seen[self.idx_buf[cur_pos - istride]] = cur_pos;
278 }
279 if x8 + x > 0 {
280 let src_idx = cur_pos - 1;
281 if last_seen[self.idx_buf[src_idx]] != cur_pos {
282 cand_list.push(self.idx_buf[src_idx]);
283 last_seen[self.idx_buf[src_idx]] = cur_pos;
284 }
285 }
286 if (y > 0) && (x8 + x > 0) {
287 let src_idx = cur_pos - 1 - istride;
288 if last_seen[self.idx_buf[src_idx]] != cur_pos {
289 cand_list.push(self.idx_buf[src_idx]);
290 last_seen[self.idx_buf[src_idx]] = cur_pos;
291 }
292 }
293 if (y > 0) && (x8 + x + 1 < istride) {
294 let src_idx = cur_pos + 1 - istride;
295 if last_seen[self.idx_buf[src_idx]] != cur_pos {
296 cand_list.push(self.idx_buf[src_idx]);
297 last_seen[self.idx_buf[src_idx]] = cur_pos;
298 }
299 }
300 if y > 1 {
301 let src_idx = cur_pos - 2 * istride;
302 if last_seen[self.idx_buf[src_idx]] != cur_pos {
303 cand_list.push(self.idx_buf[src_idx]);
304 last_seen[self.idx_buf[src_idx]] = cur_pos;
305 }
306 }
307
308 validate!(!cand_list.is_empty());
309 self.idx_buf[cur_pos] = match cand_list.len() {
310 1 => cand_list[0],
311 2 => cand_list[br.read(1)? as usize],
312 _ => {
313 let idx = br.read(2)? as usize;
314 validate!(idx < cand_list.len());
315 cand_list[idx]
316 },
317 };
318 if y > 0 {
319 self.add_to_context(self.idx_buf[cur_pos - istride], self.idx_buf[cur_pos]);
320 }
321 },
322 2 => {
323 validate!(y > 0);
324 let top_idx = self.idx_buf[pos + x - istride];
325 let delta = br.read(4)? as usize + 1;
326 self.idx_buf[pos + x] = if !br.read_bool()? {
327 validate!(top_idx + delta < num_tiles);
328 top_idx + delta
329 } else {
330 validate!(top_idx >= delta);
331 top_idx - delta
332 };
333 if y > 0 {
334 self.add_to_context(self.idx_buf[pos + x - istride], self.idx_buf[pos + x]);
335 }
336 },
337 _ => {
338 validate!(y > 0);
339 let idx = br.read(4)? as usize;
340 self.idx_buf[pos + x] = self.contexts[self.idx_buf[pos + x - istride]][idx];
341 },
342 }
343 }
344 }
345 }
346 }
347 ypos += istride;
348 }
349
350 for (dline, sline) in dst.chunks_mut(stride).take(height).zip(self.idx_buf.chunks_exact(istride)) {
351 for (dst, &idx) in dline.chunks_exact_mut(tsize).zip(sline.iter()) {
352 if idx != 0 || is_intra {
353 dst.copy_from_slice(&self.tiles[idx * tsize..][..tsize]);
354 }
355 }
356 }
357
358 Ok((NABufferType::Video(vbuf), is_intra))
359 }
360 }
361
362 const RGBA_FORMAT: NAPixelFormaton = NAPixelFormaton {
363 model: ColorModel::RGB(RGBSubmodel::RGB), components: 4,
364 comp_info: [
365 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 4 }),
366 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 4 }),
367 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 4 }),
368 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 3, next_elem: 4 }),
369 None ],
370 elem_size: 4, be: false, alpha: true, palette: false };
371
372 impl NADecoder for ArxelVideoDecoder {
373 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
374 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
375 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), true, RGBA_FORMAT));
376 if let Some(edata) = info.get_extradata() {
377 validate!(!edata.is_empty());
378 if edata[0] > 1 {
379 return Err(DecoderError::NotImplemented);
380 }
381 self.version = edata[0];
382 }
383 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
384
385 Ok(())
386 } else {
387 Err(DecoderError::InvalidData)
388 }
389 }
390 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
391 let src = pkt.get_buffer();
392 validate!(src.len() > HEADER_SIZE);
393
394 let (bufinfo, is_intra) = match self.version {
395 0 => self.decode_v1(&src)?,
396 1 => self.decode_v2(&src)?,
397 _ => return Err(DecoderError::NotImplemented),
398 };
399
400 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
401 frm.set_keyframe(is_intra);
402 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
403 Ok(frm.into_ref())
404 }
405 fn flush(&mut self) {
406 self.hams.clear();
407 }
408 }
409
410 impl NAOptionHandler for ArxelVideoDecoder {
411 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
412 fn set_options(&mut self, _options: &[NAOption]) { }
413 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
414 }
415
416
417 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
418 Box::new(ArxelVideoDecoder::new())
419 }
420
421 #[cfg(test)]
422 mod test {
423 use nihav_core::codecs::RegisteredDecoders;
424 use nihav_core::demuxers::RegisteredDemuxers;
425 use nihav_codec_support::test::dec_video::*;
426 use crate::game_register_all_decoders;
427 use crate::game_register_all_demuxers;
428 // sample from the Ring game
429 #[test]
430 fn test_arxel_video() {
431 let mut dmx_reg = RegisteredDemuxers::new();
432 game_register_all_demuxers(&mut dmx_reg);
433 let mut dec_reg = RegisteredDecoders::new();
434 game_register_all_decoders(&mut dec_reg);
435
436 test_decoding("arxel-cnm", "arxel-video", "assets/Game/logo.cnm", Some(10), &dmx_reg, &dec_reg,
437 ExpectedTestResult::MD5([0x9b1fc970, 0x1fe86e2c, 0x44dd9255, 0x3920c49b]));
438 }
439 // sample from Faust: The Seven Games of the Soul game
440 #[test]
441 fn test_arxel_video_v2() {
442 let mut dmx_reg = RegisteredDemuxers::new();
443 game_register_all_demuxers(&mut dmx_reg);
444 let mut dec_reg = RegisteredDecoders::new();
445 game_register_all_decoders(&mut dec_reg);
446
447 test_decoding("arxel-cnm", "arxel-video", "assets/Game/logo.CI2", Some(10), &dmx_reg, &dec_reg,
448 ExpectedTestResult::MD5([0x3bf66a39, 0x6627f529, 0x4ed19e8e, 0xc0693aae]));
449 }
450 }