1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use nihav_core::io::bitreader::*;
4 use nihav_codec_support::codecs::HAMShuffler;
6 const HEADER_SIZE: usize = 0x2F;
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)
18 struct ArxelVideoDecoder {
23 contexts: [[usize; 16]; 4096],
24 ctx_pos: [usize; 4096],
25 hams: HAMShuffler<u8>,
28 impl ArxelVideoDecoder {
31 info: NACodecInfoRef::default(),
35 contexts: [[0; 16]; 4096],
37 hams: HAMShuffler::new(),
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);
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;
54 let vinfo = self.info.get_properties().get_video_info().unwrap();
55 validate!(width == vinfo.get_width());
56 validate!(height == vinfo.get_height());
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;
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 {
69 self.tiles[tile * tsize + i] = self.tiles[tile * tsize + i - tsize];
71 let bits = bir.read(3)? as u8 + 1;
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()? {
78 *el = (i16::from(*el) + delta) as u8;
83 validate!(tile_size == num_tiles * tsize);
84 br.read_buf(&mut self.tiles[..tile_size])?;
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();
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]);
105 let (mv_x, mv_y) = if br.read_bool()? {
107 } else if br.read_bool()? {
108 MV_2BIT[br.read(2)? as usize]
110 MV_4BIT[br.read(4)? as usize]
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]);
122 let lines = &mut dst[y * stride..];
123 let (src, dst) = lines.split_at_mut(stride);
124 dst[..stride].copy_from_slice(src);
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;
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);
139 let mut has_tiles = false;
140 let mut is_55 = false;
142 let ftype = br.read_byte()?;
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;
149 let tile_w = if tile_size == 2 { 2 } else { 4 };
150 let tsize = tile_w * BPP;
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..]);
162 let bits = bir.read(3)? as u8;
166 for i in 0..tile_size {
167 let el = &mut cur_tile[i * BPP + comp];
173 let mut delta = bir.read(bits)? as i16;
174 if delta != 0 && bir.read_bool()? {
177 (i16::from(*el) + delta) as u8
183 br.read_skip(size - tsize)?;
196 _ => return Err(DecoderError::InvalidData),
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;
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;
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()
222 if let Some(buf) = self.hams.clone_ref() {
225 return Err(DecoderError::MissingReference);
228 let stride = vbuf.get_stride(0);
229 let data = vbuf.get_data_mut().unwrap();
230 let dst = data.as_mut_slice();
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;
240 let start = br.tell() as usize;
241 let mut br = BitReader::new(&src[start..], BitReaderMode::LE);
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];
251 for x8 in (0..istride).step_by(8) {
256 self.idx_buf[pos + x] = self.idx_buf[pos + x - istride];
262 self.idx_buf[pos + x] = self.idx_buf[pos + x - istride];
264 let mode = br.read(2)?;
267 let idx = br.read(idx_bits)? as usize;
268 self.idx_buf[pos + x] = idx;
270 self.add_to_context(self.idx_buf[pos + x - istride], idx);
275 let cur_pos = pos + x;
277 last_seen[self.idx_buf[cur_pos - istride]] = cur_pos;
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;
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;
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;
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;
308 validate!(!cand_list.is_empty());
309 self.idx_buf[cur_pos] = match cand_list.len() {
311 2 => cand_list[br.read(1)? as usize],
313 let idx = br.read(2)? as usize;
314 validate!(idx < cand_list.len());
319 self.add_to_context(self.idx_buf[cur_pos - istride], self.idx_buf[cur_pos]);
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);
330 validate!(top_idx >= delta);
334 self.add_to_context(self.idx_buf[pos + x - istride], self.idx_buf[pos + x]);
339 let idx = br.read(4)? as usize;
340 self.idx_buf[pos + x] = self.contexts[self.idx_buf[pos + x - istride]][idx];
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]);
358 Ok((NABufferType::Video(vbuf), is_intra))
362 const RGBA_FORMAT: NAPixelFormaton = NAPixelFormaton {
363 model: ColorModel::RGB(RGBSubmodel::RGB), components: 4,
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 }),
370 elem_size: 4, be: false, alpha: true, palette: false };
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());
379 return Err(DecoderError::NotImplemented);
381 self.version = edata[0];
383 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
387 Err(DecoderError::InvalidData)
390 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
391 let src = pkt.get_buffer();
392 validate!(src.len() > HEADER_SIZE);
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),
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 });
405 fn flush(&mut self) {
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 }
417 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
418 Box::new(ArxelVideoDecoder::new())
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
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);
436 test_decoding("arxel-cnm", "arxel-video", "assets/Game/logo.cnm", Some(10), &dmx_reg, &dec_reg,
437 ExpectedTestResult::MD5([0x9b1fc970, 0x1fe86e2c, 0x44dd9255, 0x3920c49b]));
439 // sample from Faust: The Seven Games of the Soul game
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);
447 test_decoding("arxel-cnm", "arxel-video", "assets/Game/logo.CI2", Some(10), &dmx_reg, &dec_reg,
448 ExpectedTestResult::MD5([0x3bf66a39, 0x6627f529, 0x4ed19e8e, 0xc0693aae]));