From 4d126e09f277356b19c3090206bd01f9ebf13aa5 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sat, 14 Sep 2024 11:29:35 +0200 Subject: [PATCH] remove Arxel Tribe CNM decoding support It has been moved to na_game_tool. --- nihav-game/Cargo.toml | 7 +- nihav-game/src/codecs/arxel_vid.rs | 450 ----------------------------- nihav-game/src/codecs/mod.rs | 4 - nihav-game/src/demuxers/cnm.rs | 288 ------------------ nihav-game/src/demuxers/mod.rs | 4 - 5 files changed, 3 insertions(+), 750 deletions(-) delete mode 100644 nihav-game/src/codecs/arxel_vid.rs delete mode 100644 nihav-game/src/demuxers/cnm.rs diff --git a/nihav-game/Cargo.toml b/nihav-game/Cargo.toml index af489f3..253bbd5 100644 --- a/nihav-game/Cargo.toml +++ b/nihav-game/Cargo.toml @@ -18,7 +18,7 @@ nihav_commonfmt = { path = "../nihav-commonfmt", default-features=false, feature [features] default = ["all_decoders", "all_demuxers", "all_muxers"] demuxers = [] -all_demuxers = ["demuxer_bmv", "demuxer_bmv3", "demuxer_cnm", "demuxer_fcmp", "demuxer_fst", "demuxer_gdv", "demuxer_hl_fmv", "demuxer_imax", "demuxer_q", "demuxer_rbt", "demuxer_seq", "demuxer_sga", "demuxer_siff", "demuxer_smush", "demuxer_vmd", "demuxer_vx"] +all_demuxers = ["demuxer_bmv", "demuxer_bmv3", "demuxer_fcmp", "demuxer_fst", "demuxer_gdv", "demuxer_hl_fmv", "demuxer_imax", "demuxer_q", "demuxer_rbt", "demuxer_seq", "demuxer_sga", "demuxer_siff", "demuxer_smush", "demuxer_vmd", "demuxer_vx"] demuxer_bmv = ["demuxers"] demuxer_bmv3 = ["demuxers"] demuxer_cnm = ["demuxers"] @@ -39,8 +39,7 @@ demuxer_vx = ["demuxers"] all_decoders = ["all_video_decoders", "all_audio_decoders"] decoders = [] -all_video_decoders = ["decoder_arxel_vid", "decoder_beam_fcp", "decoder_beam_vbv", "decoder_bmv", "decoder_bmv3", "decoder_fstvid", "decoder_gdvvid", "decoder_hl_fmv", "decoder_imax", "decoder_ipma", "decoder_midivid", "decoder_midivid3", "decoder_q", "decoder_rbt", "decoder_seq", "decoder_sga", "decoder_smush_video", "decoder_vmd", "decoder_vx"] -decoder_arxel_vid = ["decoders"] +all_video_decoders = ["decoder_beam_fcp", "decoder_beam_vbv", "decoder_bmv", "decoder_bmv3", "decoder_fstvid", "decoder_gdvvid", "decoder_hl_fmv", "decoder_imax", "decoder_ipma", "decoder_midivid", "decoder_midivid3", "decoder_q", "decoder_rbt", "decoder_seq", "decoder_sga", "decoder_smush_video", "decoder_vmd", "decoder_vx"] decoder_beam_fcp = ["decoders"] decoder_beam_vbv = ["decoders"] decoder_bmv = ["decoders"] @@ -67,4 +66,4 @@ decoder_smush_audio = ["decoders"] all_muxers = ["muxer_ea"] muxers = [] -muxer_ea = ["muxers"] \ No newline at end of file +muxer_ea = ["muxers"] diff --git a/nihav-game/src/codecs/arxel_vid.rs b/nihav-game/src/codecs/arxel_vid.rs deleted file mode 100644 index 269b2c0..0000000 --- a/nihav-game/src/codecs/arxel_vid.rs +++ /dev/null @@ -1,450 +0,0 @@ -use nihav_core::codecs::*; -use nihav_core::io::byteio::*; -use nihav_core::io::bitreader::*; -use nihav_codec_support::codecs::HAMShuffler; - -const HEADER_SIZE: usize = 0x2F; - -const MV_2BIT: [(i8, i8); 4] = [(-1, 0), (-1, -1), (1, -1), (0, -2)]; -const MV_4BIT: [(i8, i8); 16] = [ - (-2, -3), ( 2, -3), (-1, -4), ( 1, -4), - (-1, -2), ( 1, -2), ( 0, -3), ( 0, -4), - (-2, 0), (-2, -1), ( 2, -1), (-2, -2), - ( 2, -2), (-1, -3), ( 1, -3), ( 0, -5) -]; - -const BPP: usize = 4; - -struct ArxelVideoDecoder { - info: NACodecInfoRef, - tiles: [u8; 65536], - version: u8, - idx_buf: Vec, - contexts: [[usize; 16]; 4096], - ctx_pos: [usize; 4096], - hams: HAMShuffler, -} - -impl ArxelVideoDecoder { - fn new() -> Self { - Self { - info: NACodecInfoRef::default(), - tiles: [0; 65536], - version: 0, - idx_buf: Vec::new(), - contexts: [[0; 16]; 4096], - ctx_pos: [0; 4096], - hams: HAMShuffler::new(), - } - } - fn decode_v1(&mut self, src: &[u8]) -> DecoderResult<(NABufferType, bool)> { - let mut mr = MemoryReader::new_read(src); - let mut br = ByteReader::new(&mut mr); - - let size = br.read_u32le()? as usize; - validate!(src.len() >= size + HEADER_SIZE); - let part2_off = br.read_u32le()? as u64; - validate!(part2_off > 0 && part2_off < (size as u64)); - let num_tiles = br.read_u16le()? as usize; - validate!(num_tiles > 0 && num_tiles < 4096); - let tile_size = br.read_u16le()? as usize; - let width = br.read_u32le()? as usize; - let height = br.read_u32le()? as usize; - - let vinfo = self.info.get_properties().get_video_info().unwrap(); - validate!(width == vinfo.get_width()); - validate!(height == vinfo.get_height()); - - br.seek(SeekFrom::Start(part2_off + (HEADER_SIZE as u64)))?; - let tile_w = if tile_size == 2 { 2 } else { 4 }; - let tsize = tile_w * BPP; - - match tile_size { - 2 | 4 => { - br.read_buf(&mut self.tiles[..tsize])?; - let off = br.tell() as usize; - let mut bir = BitReader::new(&src[off..], BitReaderMode::BE); - for tile in 1..num_tiles { - for i in 0..tsize { - self.tiles[tile * tsize + i] = self.tiles[tile * tsize + i - tsize]; - } - let bits = bir.read(3)? as u8 + 1; - validate!(bits < 8); - for el in self.tiles[tile * tsize..][..tsize].iter_mut() { - let mut delta = bir.read(bits)? as i16; - if delta != 0 && bir.read_bool()? { - delta = -delta; - } - *el = (i16::from(*el) + delta) as u8; - } - } - }, - _ => { - validate!(tile_size == num_tiles * tsize); - br.read_buf(&mut self.tiles[..tile_size])?; - }, - }; - - let bufinfo = alloc_video_buffer(vinfo, 0)?; - let bufo = bufinfo.get_vbuf(); - let mut buf = bufo.unwrap(); - let stride = buf.get_stride(0); - let data = buf.get_data_mut().unwrap(); - let dst = data.as_mut_slice(); - - let mut br = BitReader::new(&src[HEADER_SIZE..], BitReaderMode::BE); - let idx_bits = if num_tiles < 0x400 { 10 } else if num_tiles < 0x800 { 11 } else { 12 }; - for y in (0..height).step_by(2) { - for x in (0..width).step_by(tile_w) { - let dst_pos = x * BPP + y * stride; - if !br.read_bool()? { - let idx = br.read(idx_bits)? as usize; - validate!(idx < num_tiles); - dst[dst_pos..][..tsize].copy_from_slice(&self.tiles[idx * tsize..][..tsize]); - } else { - let (mv_x, mv_y) = if br.read_bool()? { - (0, -1) - } else if br.read_bool()? { - MV_2BIT[br.read(2)? as usize] - } else { - MV_4BIT[br.read(4)? as usize] - }; - - let isrc = (dst_pos as isize) + isize::from(mv_x) * (tsize as isize) + isize::from(mv_y) * ((stride * 2) as isize); - validate!(isrc >= 0); - let src_pos = isrc as usize; - validate!(src_pos + tsize <= dst.len()); - let (src, dst) = dst.split_at_mut(dst_pos); - dst[..tsize].copy_from_slice(&src[src_pos..][..tsize]); - } - } - // double lines - let lines = &mut dst[y * stride..]; - let (src, dst) = lines.split_at_mut(stride); - dst[..stride].copy_from_slice(src); - } - Ok((bufinfo, true)) - } - fn add_to_context(&mut self, prev: usize, cur: usize) { - self.contexts[prev][self.ctx_pos[prev]] = cur; - self.ctx_pos[prev] += 1; - if self.ctx_pos[prev] == 16 { - self.ctx_pos[prev] = 0; - } - } - fn decode_v2(&mut self, src: &[u8]) -> DecoderResult<(NABufferType, bool)> { - let mut mr = MemoryReader::new_read(src); - let mut br = ByteReader::new(&mut mr); - - let mut has_tiles = false; - let mut is_55 = false; - loop { - let ftype = br.read_byte()?; - match ftype { - 0x54 => { - let size = br.read_u32le()? as usize; - let num_tiles = br.read_u16le()? as usize; - let tile_size = br.read_u16le()? as usize; - - let tile_w = if tile_size == 2 { 2 } else { 4 }; - let tsize = tile_w * BPP; - - match tile_size { - 2 | 4 => { - validate!(size >= tsize); - br.read_buf(&mut self.tiles[..tsize])?; - let off = br.tell() as usize; - let mut bir = BitReader::new(&src[off..][..size - tsize], BitReaderMode::LE); - for tile in 1..num_tiles { - let (prev_tiles, cur_tile) = self.tiles.split_at_mut(tile * tsize); - cur_tile[..16].copy_from_slice(&prev_tiles[prev_tiles.len() - 16..]); - for comp in 0..BPP { - let bits = bir.read(3)? as u8; - if bits == 0 { - continue; - } - for i in 0..tile_size { - let el = &mut cur_tile[i * BPP + comp]; - *el = match bits { - 7 => { - bir.read(8)? as u8 - }, - _ => { - let mut delta = bir.read(bits)? as i16; - if delta != 0 && bir.read_bool()? { - delta = -delta; - } - (i16::from(*el) + delta) as u8 - }, - }; - } - } - } - br.read_skip(size - tsize)?; - has_tiles = true; - }, - _ => { - unimplemented!(); - }, - }; - }, - 0x53 => break, - 0x55 => { - is_55 = true; - break; - }, - _ => return Err(DecoderError::InvalidData), - }; - } - - let size = br.read_u32le()? as usize; - validate!(size + HEADER_SIZE <= (br.left() as usize) + 4); - let part2_off = br.read_u32le()?; - validate!(part2_off as usize == size); - let num_tiles = br.read_u16le()? as usize; - validate!((0..4096).contains(&num_tiles)); - let tile_size = br.read_u16le()? as usize; - let width = br.read_u32le()? as usize; - let height = br.read_u32le()? as usize; - br.read_skip(0x1B)?; - - let vinfo = self.info.get_properties().get_video_info().unwrap(); - validate!(width == vinfo.get_width()); - validate!(height == vinfo.get_height()); - let is_intra = is_55 && has_tiles; - - let mut vbuf = if is_intra { - let binfo = alloc_video_buffer(vinfo, 0)?; - let vbuf = binfo.get_vbuf().unwrap(); - self.hams.add_frame(vbuf); - self.hams.get_output_frame().unwrap() - } else { - if let Some(buf) = self.hams.clone_ref() { - buf - } else { - return Err(DecoderError::MissingReference); - } - }; - let stride = vbuf.get_stride(0); - let data = vbuf.get_data_mut().unwrap(); - let dst = data.as_mut_slice(); - - let tile_w = if tile_size == 2 { 2 } else { 4 }; - let tsize = tile_w * BPP; - let mut idx_bits = 0; - let mut v = num_tiles; - while v > 0 { - idx_bits += 1; - v >>= 1; - } - let start = br.tell() as usize; - let mut br = BitReader::new(&src[start..], BitReaderMode::LE); - let mut ypos = 0; - let mut last_seen = [0usize.wrapping_sub(1); 4096]; - let mut cand_list = Vec::with_capacity(4); - let istride = width / tile_w; - self.idx_buf.resize(istride * height, 0); - self.contexts = [[0; 16]; 4096]; - self.ctx_pos = [0; 4096]; - - for y in 0..height { - for x8 in (0..istride).step_by(8) { - let pos = ypos + x8; - if br.read_bool()? { - validate!(y > 0); - for x in 0..8 { - self.idx_buf[pos + x] = self.idx_buf[pos + x - istride]; - } - } else { - for x in 0..8 { - if br.read_bool()? { - validate!(y > 0); - self.idx_buf[pos + x] = self.idx_buf[pos + x - istride]; - } else { - let mode = br.read(2)?; - match mode { - 0 => { - let idx = br.read(idx_bits)? as usize; - self.idx_buf[pos + x] = idx; - if y > 0 { - self.add_to_context(self.idx_buf[pos + x - istride], idx); - } - }, - 1 => { - cand_list.clear(); - let cur_pos = pos + x; - if y > 0 { - last_seen[self.idx_buf[cur_pos - istride]] = cur_pos; - } - if x8 + x > 0 { - let src_idx = cur_pos - 1; - if last_seen[self.idx_buf[src_idx]] != cur_pos { - cand_list.push(self.idx_buf[src_idx]); - last_seen[self.idx_buf[src_idx]] = cur_pos; - } - } - if (y > 0) && (x8 + x > 0) { - let src_idx = cur_pos - 1 - istride; - if last_seen[self.idx_buf[src_idx]] != cur_pos { - cand_list.push(self.idx_buf[src_idx]); - last_seen[self.idx_buf[src_idx]] = cur_pos; - } - } - if (y > 0) && (x8 + x + 1 < istride) { - let src_idx = cur_pos + 1 - istride; - if last_seen[self.idx_buf[src_idx]] != cur_pos { - cand_list.push(self.idx_buf[src_idx]); - last_seen[self.idx_buf[src_idx]] = cur_pos; - } - } - if y > 1 { - let src_idx = cur_pos - 2 * istride; - if last_seen[self.idx_buf[src_idx]] != cur_pos { - cand_list.push(self.idx_buf[src_idx]); - last_seen[self.idx_buf[src_idx]] = cur_pos; - } - } - - validate!(!cand_list.is_empty()); - self.idx_buf[cur_pos] = match cand_list.len() { - 1 => cand_list[0], - 2 => cand_list[br.read(1)? as usize], - _ => { - let idx = br.read(2)? as usize; - validate!(idx < cand_list.len()); - cand_list[idx] - }, - }; - if y > 0 { - self.add_to_context(self.idx_buf[cur_pos - istride], self.idx_buf[cur_pos]); - } - }, - 2 => { - validate!(y > 0); - let top_idx = self.idx_buf[pos + x - istride]; - let delta = br.read(4)? as usize + 1; - self.idx_buf[pos + x] = if !br.read_bool()? { - validate!(top_idx + delta < num_tiles); - top_idx + delta - } else { - validate!(top_idx >= delta); - top_idx - delta - }; - if y > 0 { - self.add_to_context(self.idx_buf[pos + x - istride], self.idx_buf[pos + x]); - } - }, - _ => { - validate!(y > 0); - let idx = br.read(4)? as usize; - self.idx_buf[pos + x] = self.contexts[self.idx_buf[pos + x - istride]][idx]; - }, - } - } - } - } - } - ypos += istride; - } - - for (dline, sline) in dst.chunks_mut(stride).take(height).zip(self.idx_buf.chunks_exact(istride)) { - for (dst, &idx) in dline.chunks_exact_mut(tsize).zip(sline.iter()) { - if idx != 0 || is_intra { - dst.copy_from_slice(&self.tiles[idx * tsize..][..tsize]); - } - } - } - - Ok((NABufferType::Video(vbuf), is_intra)) - } -} - -const RGBA_FORMAT: NAPixelFormaton = NAPixelFormaton { - model: ColorModel::RGB(RGBSubmodel::RGB), components: 4, - comp_info: [ - Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 4 }), - Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 4 }), - Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 4 }), - Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 3, next_elem: 4 }), - None ], - elem_size: 4, be: false, alpha: true, palette: false }; - -impl NADecoder for ArxelVideoDecoder { - fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { - if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { - let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), true, RGBA_FORMAT)); - if let Some(edata) = info.get_extradata() { - validate!(!edata.is_empty()); - if edata[0] > 1 { - return Err(DecoderError::NotImplemented); - } - self.version = edata[0]; - } - self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); - - Ok(()) - } else { - Err(DecoderError::InvalidData) - } - } - fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult { - let src = pkt.get_buffer(); - validate!(src.len() > HEADER_SIZE); - - let (bufinfo, is_intra) = match self.version { - 0 => self.decode_v1(&src)?, - 1 => self.decode_v2(&src)?, - _ => return Err(DecoderError::NotImplemented), - }; - - let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); - frm.set_keyframe(is_intra); - frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); - Ok(frm.into_ref()) - } - fn flush(&mut self) { - self.hams.clear(); - } -} - -impl NAOptionHandler for ArxelVideoDecoder { - fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } - fn set_options(&mut self, _options: &[NAOption]) { } - fn query_option_value(&self, _name: &str) -> Option { None } -} - - -pub fn get_decoder() -> Box { - Box::new(ArxelVideoDecoder::new()) -} - -#[cfg(test)] -mod test { - use nihav_core::codecs::RegisteredDecoders; - use nihav_core::demuxers::RegisteredDemuxers; - use nihav_codec_support::test::dec_video::*; - use crate::game_register_all_decoders; - use crate::game_register_all_demuxers; - // sample from the Ring game - #[test] - fn test_arxel_video() { - let mut dmx_reg = RegisteredDemuxers::new(); - game_register_all_demuxers(&mut dmx_reg); - let mut dec_reg = RegisteredDecoders::new(); - game_register_all_decoders(&mut dec_reg); - - test_decoding("arxel-cnm", "arxel-video", "assets/Game/logo.cnm", Some(10), &dmx_reg, &dec_reg, - ExpectedTestResult::MD5([0x9b1fc970, 0x1fe86e2c, 0x44dd9255, 0x3920c49b])); - } - // sample from Faust: The Seven Games of the Soul game - #[test] - fn test_arxel_video_v2() { - let mut dmx_reg = RegisteredDemuxers::new(); - game_register_all_demuxers(&mut dmx_reg); - let mut dec_reg = RegisteredDecoders::new(); - game_register_all_decoders(&mut dec_reg); - - test_decoding("arxel-cnm", "arxel-video", "assets/Game/logo.CI2", Some(10), &dmx_reg, &dec_reg, - ExpectedTestResult::MD5([0x3bf66a39, 0x6627f529, 0x4ed19e8e, 0xc0693aae])); - } -} diff --git a/nihav-game/src/codecs/mod.rs b/nihav-game/src/codecs/mod.rs index af23b68..c4e2e2a 100644 --- a/nihav-game/src/codecs/mod.rs +++ b/nihav-game/src/codecs/mod.rs @@ -10,8 +10,6 @@ macro_rules! validate { ($a:expr) => { if !$a { return Err(DecoderError::InvalidData); } }; } -#[cfg(feature="decoder_arxel_vid")] -pub mod arxel_vid; #[cfg(any(feature="decoder_beam_vbv",feature="decoder_beam_fcp"))] pub mod beam; #[cfg(feature="decoder_bmv")] @@ -56,8 +54,6 @@ const GAME_CODECS: &[DecoderInfo] = &[ DecoderInfo { name: "gdv-audio", get_decoder: gremlinvideo::get_decoder_audio }, #[cfg(feature="decoder_gdvvid")] DecoderInfo { name: "gdv-video", get_decoder: gremlinvideo::get_decoder_video }, -#[cfg(feature="decoder_arxel_vid")] - DecoderInfo { name: "arxel-video", get_decoder: arxel_vid::get_decoder }, #[cfg(feature="decoder_beam_fcp")] DecoderInfo { name: "beam-fcp", get_decoder: beam::get_decoder_fcp }, #[cfg(feature="decoder_beam_vbv")] diff --git a/nihav-game/src/demuxers/cnm.rs b/nihav-game/src/demuxers/cnm.rs deleted file mode 100644 index e9e6126..0000000 --- a/nihav-game/src/demuxers/cnm.rs +++ /dev/null @@ -1,288 +0,0 @@ -use nihav_core::frame::*; -use nihav_core::demuxers::*; - -struct ArxelCinemaDemuxer<'a> { - src: &'a mut ByteReader<'a>, - cur_frame: usize, - astreams: usize, - offsets: Vec, - vpts: u64, - tb_num: u32, - tb_den: u32, - is_ci2: bool, - tdata: Vec, -} - -impl<'a> DemuxCore<'a> for ArxelCinemaDemuxer<'a> { - #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { - let src = &mut self.src; - - let magic = src.read_tag()?; - validate!(&magic == b"CNM "); - let magic = src.read_tag()?; - validate!(&magic == b"UNR\x00"); - let _duration = src.read_u32le()?; - let tb_den = src.read_u32le()?; - src.read_byte()?; - let width = src.read_u32le()? as usize; - let height = src.read_u32le()? as usize; - validate!(width != 0 && height != 0); - src.read_u16le()?; - self.astreams = src.read_byte()? as usize; - validate!(self.astreams < 4); - if self.astreams > 1 { - return Err(DemuxerError::NotImplemented); - } - let nframes = src.read_u32le()? as usize; - src.read_u32le()?; //nframes again? - let tab_size = src.read_u32le()? as usize; - src.read_skip(0x98)?; - - let vhdr = NAVideoInfo::new(width, height, true, RGB24_FORMAT); - let vci = NACodecTypeInfo::Video(vhdr); - // use tab_size mismatch as the version marker - let vinfo = NACodecInfo::new("arxel-video", vci, Some(vec![(tab_size != nframes * 8) as u8])); - if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 100, tb_den, nframes as u64)).is_none() { - return Err(DemuxerError::MemoryError); - } - if let Some(stream) = strmgr.get_stream_by_id(0) { - let (tb_num, tb_den) = stream.get_timebase(); - self.tb_num = tb_num; - self.tb_den = tb_den; - } - - for trk in 0..(self.astreams as u32) { - let channels = src.read_byte()? + 1; - let abits = src.read_byte()?; - let arate = src.read_u32le()?; - src.read_skip(10)?; - validate!(channels > 0); - validate!(abits >= 8); - validate!(arate > 0); - - let ahdr = NAAudioInfo::new(arate, channels, if abits > 8 { SND_S16_FORMAT } else { SND_U8_FORMAT }, 2); - let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None); - if strmgr.add_stream(NAStream::new(StreamType::Audio, 1 + trk, ainfo, 1, arate, 0)).is_none() { - return Err(DemuxerError::MemoryError); - } - } - - if tab_size == nframes * 8 { - let tab_size = tab_size / 4; - self.offsets = Vec::with_capacity(tab_size); - for _ in 0..tab_size { - let offset = src.read_u32le()?; - self.offsets.push(offset); - } - } else { - validate!(nframes > 0); - let off0 = src.read_u32le()?; - let off1 = src.read_u32le()?; - if off0 == 0 && off1 == 0 { - self.is_ci2 = true; - src.read_skip((nframes - 1) * 8)?; - } else { - return Err(DemuxerError::InvalidData); - } - } - self.cur_frame = 0; - self.vpts = 0; - Ok(()) - } - - #[allow(unused_variables)] - fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult { - loop { - let stream_id; - if !self.is_ci2 { - if self.cur_frame >= self.offsets.len() { return Err(DemuxerError::EOF); } - let pos = u64::from(self.offsets[self.cur_frame]); - stream_id = (self.cur_frame % (self.astreams.max(1) + 1)) as u32; - self.cur_frame += 1; - if pos == 0 { - continue; - } - self.src.seek(SeekFrom::Start(pos))?; - } else { - stream_id = 1; - } - let ftype = match self.src.read_byte() { - Ok(b) => b, - Err(ByteIOError::EOF) if self.is_ci2 => return Err(DemuxerError::EOF), - _ => return Err(DemuxerError::IOError), - }; - match ftype { - 0x41 | 0x42 | 0x5A => { - let size = self.src.read_u32le()? as usize; - if size == 0 { - continue; - } - if let Some(stream) = strmgr.get_stream_by_id(stream_id) { - let ts = stream.make_ts(None, None, None); - return self.src.read_packet(stream, ts, true, size); - } else { - self.src.read_skip(size)?; - } - }, - 0x53 if !self.is_ci2 => { - let size = self.src.peek_u32le()? as usize; - if let Some(stream) = strmgr.get_stream_by_id(0) { - let ts = stream.make_ts(Some(self.vpts), None, None); - self.vpts += 1; - return self.src.read_packet(stream, ts, true, size + 0x2F); - } else { - return Err(DemuxerError::MemoryError); - } - }, - 0x53 | 0x55 => { - let size = self.src.peek_u32le()? as usize; - let mut data = Vec::new(); - std::mem::swap(&mut self.tdata, &mut data); - data.push(ftype); - let head_size = data.len(); - data.resize(head_size + size + 0x2F, 0); - self.src.read_buf(&mut data[head_size..])?; - if let Some(stream) = strmgr.get_stream_by_id(0) { - let ts = stream.make_ts(Some(self.vpts), None, None); - self.vpts += 1; - return Ok(NAPacket::new(stream, ts, ftype == 0x55, data)); - } else { - return Err(DemuxerError::MemoryError); - } - }, - 0x54 => { - validate!(self.is_ci2); - let size = self.src.peek_u32le()? as usize; - validate!(self.tdata.is_empty()); - self.tdata.resize(size + 9, 0); - self.tdata[0] = 0x54; - self.src.read_buf(&mut self.tdata[1..])?; - }, - _ => continue, - }; - } - } - - fn seek(&mut self, time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> { - if self.is_ci2 { - return Err(DemuxerError::NotPossible); - } - match time { - NATimePoint::PTS(pts) => self.seek_to_frame(pts), - NATimePoint::Milliseconds(ms) => { - if self.tb_num == 0 || self.tb_den == 0 { - return Err(DemuxerError::NotPossible); - } - let pts = NATimeInfo::time_to_ts(ms, 1000, self.tb_num, self.tb_den); - self.seek_to_frame(pts) - }, - _ => Err(DemuxerError::NotPossible) - } - } - fn get_duration(&self) -> u64 { 0 } -} -impl<'a> NAOptionHandler for ArxelCinemaDemuxer<'a> { - fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } - fn set_options(&mut self, _options: &[NAOption]) { } - fn query_option_value(&self, _name: &str) -> Option { None } -} -impl<'a> ArxelCinemaDemuxer<'a> { - fn new(io: &'a mut ByteReader<'a>) -> Self { - ArxelCinemaDemuxer { - src: io, - cur_frame: 0, - astreams: 0, - offsets: Vec::new(), - vpts: 0, - tb_num: 0, - tb_den: 0, - is_ci2: false, - tdata: Vec::new(), - } - } - fn seek_to_frame(&mut self, pts: u64) -> DemuxerResult<()> { - let nframe = (pts as usize) * (1 + self.astreams.max(1)); - if nframe < self.offsets.len() { - self.cur_frame = nframe; - Ok(()) - } else { - Err(DemuxerError::SeekError) - } - } -} - -pub struct CNMDemuxerCreator { } - -impl DemuxerCreator for CNMDemuxerCreator { - fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box + 'a> { - Box::new(ArxelCinemaDemuxer::new(br)) - } - fn get_name(&self) -> &'static str { "arxel-cnm" } -} - -#[cfg(test)] -mod test { - use super::*; - use std::fs::File; - - // samples from the Ring game - #[test] - fn test_cnm_demux() { - let mut file = File::open("assets/Game/logo.cnm").unwrap(); - let mut fr = FileReader::new_read(&mut file); - let mut br = ByteReader::new(&mut fr); - let mut dmx = ArxelCinemaDemuxer::new(&mut br); - let mut sm = StreamManager::new(); - let mut si = SeekIndex::new(); - dmx.open(&mut sm, &mut si).unwrap(); - loop { - let pktres = dmx.get_frame(&mut sm); - if let Err(e) = pktres { - if (e as i32) == (DemuxerError::EOF as i32) { break; } - panic!("error"); - } - let pkt = pktres.unwrap(); - println!("Got {}", pkt); - } - } - #[test] - fn test_cnm_noaud_demux() { - let mut file = File::open("assets/Game/tr_as_ro_d.cnm").unwrap(); - let mut fr = FileReader::new_read(&mut file); - let mut br = ByteReader::new(&mut fr); - let mut dmx = ArxelCinemaDemuxer::new(&mut br); - let mut sm = StreamManager::new(); - let mut si = SeekIndex::new(); - dmx.open(&mut sm, &mut si).unwrap(); - loop { - let pktres = dmx.get_frame(&mut sm); - if let Err(e) = pktres { - if (e as i32) == (DemuxerError::EOF as i32) { break; } - panic!("error"); - } - let pkt = pktres.unwrap(); - println!("Got {}", pkt); - } - } - // sample from Faust: The Seven Games of the Soul game - #[test] - fn test_ci2_demux() { - let mut file = File::open("assets/Game/logo.CI2").unwrap(); - let mut fr = FileReader::new_read(&mut file); - let mut br = ByteReader::new(&mut fr); - let mut dmx = ArxelCinemaDemuxer::new(&mut br); - let mut sm = StreamManager::new(); - let mut si = SeekIndex::new(); - dmx.open(&mut sm, &mut si).unwrap(); - loop { - let pktres = dmx.get_frame(&mut sm); - if let Err(e) = pktres { - if (e as i32) == (DemuxerError::EOF as i32) { break; } - panic!("error"); - } - let pkt = pktres.unwrap(); - println!("Got {}", pkt); - } - } -} diff --git a/nihav-game/src/demuxers/mod.rs b/nihav-game/src/demuxers/mod.rs index 3e3f842..0b3a77b 100644 --- a/nihav-game/src/demuxers/mod.rs +++ b/nihav-game/src/demuxers/mod.rs @@ -12,8 +12,6 @@ macro_rules! validate { #[cfg(any(feature="demuxer_bmv",feature="demuxer_bmv3"))] mod bmv; -#[cfg(feature="demuxer_cnm")] -mod cnm; #[cfg(any(feature="demuxer_fst",feature="demuxer_fcmp"))] mod fst; #[cfg(feature="demuxer_gdv")] @@ -44,8 +42,6 @@ const GAME_DEMUXERS: &[&dyn DemuxerCreator] = &[ &bmv::BMVDemuxerCreator {}, #[cfg(feature="demuxer_bmv3")] &bmv::BMV3DemuxerCreator {}, -#[cfg(feature="demuxer_cnm")] - &cnm::CNMDemuxerCreator {}, #[cfg(feature="demuxer_fcmp")] &fst::FCMPDemuxerCreator {}, #[cfg(feature="demuxer_fst")] -- 2.39.5