+++ /dev/null
-use nihav_core::codecs::*;
-use nihav_core::io::byteio::*;
-
-const FRAME_W: usize = 320;
-const FRAME_H: usize = 160;
-
-struct IMAXDecoder {
- info: NACodecInfoRef,
- pal: [u8; 768],
- frame: [u8; FRAME_W * FRAME_H],
- hist: [u8; 32768],
- hist_pos: usize,
-}
-
-impl IMAXDecoder {
- fn new() -> Self {
- Self {
- info: NACodecInfoRef::default(),
- pal: [0; 768],
- frame: [0; FRAME_W * FRAME_H],
- hist: [0; 32768],
- hist_pos: 0,
- }
- }
-}
-
-impl NADecoder for IMAXDecoder {
- fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
- if let NACodecTypeInfo::Video(_vinfo) = info.get_properties() {
- /*let fmt = NAPixelFormaton::new(ColorModel::RGB(RGBSubmodel::RGB),
- Some(NAPixelChromaton::new(0, 0, true, 8, 0, 0, 3)),
- Some(NAPixelChromaton::new(0, 0, true, 8, 0, 1, 3)),
- Some(NAPixelChromaton::new(0, 0, true, 8, 0, 2, 3)),
- None, None,
- FORMATON_FLAG_PALETTE, 3);*/
- let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(FRAME_W, FRAME_H, false, PAL8_FORMAT));
- 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<NAFrameRef> {
- let src = pkt.get_buffer();
- validate!(src.len() > 0);
-
- for sd in pkt.side_data.iter() {
- if let NASideData::Palette(true, ref pal) = sd {
- for (dst, src) in self.pal.chunks_mut(3).zip(pal.chunks(4)) {
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- }
- break;
- }
- }
-
- let mut mr = MemoryReader::new_read(&src);
- let mut br = ByteReader::new(&mut mr);
-
- let mut is_intra = true;
- let mut is_skip = true;
- let mut idx = 0;
- while idx < self.frame.len() {
- let v = br.read_byte()?;
- let op = v >> 6;
- let len = (v & 0x3F) as usize;
- match op {
- 0 => {
- validate!(idx + len <= self.frame.len());
- idx += len;
- is_intra = false;
- },
- 1 => {
- if len == 0 {
- let off = br.read_u16le()? as usize;
- let len = br.read_byte()? as usize;
- validate!(idx + len <= self.frame.len());
- validate!(off + len <= self.hist.len());
- self.frame[idx..][..len].copy_from_slice(&self.hist[off..][..len]);
- } else {
- validate!(idx + len <= self.frame.len());
- br.read_buf(&mut self.frame[idx..][..len])?;
- if self.hist_pos + len <= self.hist.len() {
- self.hist[self.hist_pos..][..len].copy_from_slice(&self.frame[idx..][..len]);
- self.hist_pos += len;
- }
- idx += len;
- }
- is_skip = false;
- },
- 2 => {
- let pix = br.read_byte()?;
- validate!(idx + len <= self.frame.len());
- for _ in 0..len {
- self.frame[idx] = pix;
- idx += 1;
- }
- is_skip = false;
- },
- _ => {
- let len2 = br.read_byte()? as usize;
- let skip_len = len * 64 + len2;
- validate!(idx + skip_len <= self.frame.len());
- idx += skip_len;
- is_intra = false;
- },
- };
- }
-
- let bufinfo = if !is_skip {
- let binfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
- let mut vbuf = binfo.get_vbuf().unwrap();
- let paloff = vbuf.get_offset(1);
- let stride = vbuf.get_stride(0);
- let data = vbuf.get_data_mut().unwrap();
- for (drow, srow) in data.chunks_mut(stride).zip(self.frame.chunks(FRAME_W)) {
- drow[..FRAME_W].copy_from_slice(srow);
- }
- data[paloff..][..768].copy_from_slice(&self.pal);
- binfo
- } else {
- NABufferType::None
- };
-
- let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
- frm.set_keyframe(is_intra);
- let ftype = if is_skip { FrameType::Skip } else if is_intra { FrameType::I } else { FrameType::P };
- frm.set_frame_type(ftype);
- Ok(frm.into_ref())
- }
- fn flush(&mut self) {
- }
-}
-
-impl NAOptionHandler for IMAXDecoder {
- fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
- fn set_options(&mut self, _options: &[NAOption]) { }
- fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
-}
-
-pub fn get_decoder() -> Box<dyn NADecoder + Send> {
- Box::new(IMAXDecoder::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;
- #[test]
- fn test_imax_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);
-
- // sample from Fable game
- test_decoding("fable-imax", "fable-imax", "assets/Game/present.imx",
- Some(64), &dmx_reg, &dec_reg,
- ExpectedTestResult::MD5([0x775e1326, 0x7aa63674, 0x9b8aec54, 0x5caee2e3]));
- }
-}
+++ /dev/null
-use nihav_core::frame::*;
-use nihav_core::demuxers::*;
-use std::sync::Arc;
-
-#[allow(dead_code)]
-struct IMAXDemuxer<'a> {
- src: &'a mut ByteReader<'a>,
- cur_frame: u64,
- apos: u64,
- a_id: usize,
- v_id: usize,
- pal: Arc<[u8; 1024]>,
- pal_change: bool,
-}
-
-impl<'a> DemuxCore<'a> for IMAXDemuxer<'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"IMAX");
- let nframes = u64::from(src.read_u32le()?);
- let fps = u32::from(src.read_u16le()?);
- let magic2 = src.read_u16le()?;
- validate!(magic2 == 0x102);
- let _zero = src.read_u16le()?;
- let _max_vframe_size = src.read_u32le()?;
- let _buffering_size = src.read_u32le()?;
-
- let vhdr = NAVideoInfo::new(320, 160, false, PAL8_FORMAT);
- let vci = NACodecTypeInfo::Video(vhdr);
- let vinfo = NACodecInfo::new("fable-imax", vci, None);
- self.v_id = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, fps, nframes)).unwrap();
- let ahdr = NAAudioInfo::new(22050, 1, SND_U8_FORMAT, 2);
- let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
- self.a_id = strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, 22050, 2)).unwrap();
- self.cur_frame = 0;
- self.apos = 0;
- Ok(())
- }
-
- #[allow(unused_variables)]
- fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
- loop {
- let fsize = self.src.read_u32le()? as usize;
- let ftype = self.src.read_u32le()?;
-
- match ftype {
- 0xAA97 => {
- let stream = strmgr.get_stream(self.v_id).unwrap();
- let ts = stream.make_ts(Some(self.cur_frame), None, None);
- self.cur_frame += 1;
- let mut pkt = self.src.read_packet(stream, ts, true, fsize)?;
- pkt.add_side_data(NASideData::Palette(self.pal_change, self.pal.clone()));
- self.pal_change = false;
- return Ok(pkt);
- },
- 0xAA98 => {
- validate!(fsize == 768);
- let mut pal = [0u8; 1024];
- for chunk in pal.chunks_mut(4) {
- let r = self.src.read_byte()?;
- let g = self.src.read_byte()?;
- let b = self.src.read_byte()?;
- chunk[0] = (r << 2) | (r >> 4);
- chunk[1] = (g << 2) | (g >> 4);
- chunk[2] = (b << 2) | (b >> 4);
- }
- self.pal = Arc::new(pal);
- self.pal_change = true;
- },
- 0xAA99 => {
- let stream = strmgr.get_stream(self.a_id).unwrap();
- let ts = stream.make_ts(Some(self.apos), None, None);
- self.apos += fsize as u64;
- return self.src.read_packet(stream, ts, true, fsize);
- },
- 0xAAFF => return Err(DemuxerError::EOF),
- _ => return Err(DemuxerError::InvalidData),
- }
- }
- }
-
- fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
- Err(DemuxerError::NotPossible)
- }
- fn get_duration(&self) -> u64 { 0 }
-}
-impl<'a> NAOptionHandler for IMAXDemuxer<'a> {
- fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
- fn set_options(&mut self, _options: &[NAOption]) { }
- fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
-}
-impl<'a> IMAXDemuxer<'a> {
- fn new(io: &'a mut ByteReader<'a>) -> Self {
- IMAXDemuxer {
- src: io,
- cur_frame: 0,
- apos: 0,
- a_id: 0,
- v_id: 0,
- pal: Arc::new([0; 1024]),
- pal_change: false,
- }
- }
-}
-
-pub struct IMAXDemuxerCreator { }
-
-impl DemuxerCreator for IMAXDemuxerCreator {
- fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
- Box::new(IMAXDemuxer::new(br))
- }
- fn get_name(&self) -> &'static str { "fable-imax" }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use std::fs::File;
-
- #[test]
- fn test_imax_demux() {
- // sample from Fable game
- let mut file = File::open("assets/Game/present.imx").unwrap();
- let mut fr = FileReader::new_read(&mut file);
- let mut br = ByteReader::new(&mut fr);
- let mut dmx = IMAXDemuxer::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);
- }
- }
-}