use nihav_core::demuxers::*;
+#[cfg(feature="demuxer_tca")]
+use super::tca::TCACoreDemuxer;
+
const VIDEO_CODECS: &[(i32, &str)] = &[
( 1, "movinglines"),
( 2, "arm_rawvideo"),
(122, "escape122"),
(124, "escape124"),
(130, "escape130"),
+ (500, "euclid"),
+ (600, "msvideo1"),
+ (601, "msvideo1"),
+ (602, "cinepak"),
(800, "linepack"),
(802, "movie16_3"),
];
let mut res = Vec::new();
loop {
let c = self.read_byte()?;
- if c == b'\n' {
+ if c == b'\n' || c == 0 {
break;
}
res.push(c);
state: ReadState,
video_id: Option<usize>,
audio_ids: Vec<usize>,
+ #[cfg(feature="demuxer_tca")]
+ tca: Option<TCACoreDemuxer>,
}
impl<'a> ARMovieDemuxer<'a> {
state: ReadState::None,
video_id: None,
audio_ids: Vec::new(),
+ #[cfg(feature="demuxer_tca")]
+ tca: None,
}
}
fn parse_catalogue(&mut self, offset: u32, num_chunks: usize, even_csize: usize, odd_csize: usize, aud_tracks: usize) -> DemuxerResult<()> {
}
let tot_size: u32 = vid_size + aud_sizes.iter().sum::<u32>();
- validate!((tot_size as usize) <= cur_chunk_size);
+ validate!(cur_chunk_size == 0 || (tot_size as usize) <= cur_chunk_size);
self.chunk_offs.push(ChunkInfo { offset, vid_size, aud_sizes });
} else {
return Err(DemuxerError::InvalidData);
let width = parse_int(&width)?;
let height = self.src.read_string()?;
let height = parse_int(&height)?;
- validate!((video_codec <= 0) ^ (width > 0 && height > 0));
+ validate!((video_codec <= 0) || (width > 0 && height > 0));
let width = width as usize;
let height = height as usize;
let vformat = self.src.read_string()?;
self.parse_catalogue(cat_offset, num_chunks, even_chunk_size, odd_chunk_size, num_sound)?;
+ #[cfg(feature="demuxer_tca")]
+ if video_codec == 500 {
+ validate!(fps > 1.0e-4);
+ let mut tbase = fps;
+ let mut tb_num = 1;
+ while tbase.fract() > 1.0e-4 {
+ tb_num *= 10;
+ tbase *= 10.0;
+ }
+ let tb_den = tbase as u32;
+
+ self.src.seek(SeekFrom::Start(u64::from(self.chunk_offs[0].offset)))?;
+ let mut tca = TCACoreDemuxer::default();
+ tca.open(self.src, strmgr, tb_num, tb_den)?;
+ self.tca = Some(tca);
+ return Ok(());
+ }
+
let mut stream_id = 0;
if video_codec > 0 {
let codec_name = if let Some(idx) = VIDEO_CODECS.iter().position(|&(id, _)| id == video_codec) {
let mut edata = vec![video_codec as u8, (video_codec >> 8) as u8];
edata.extend_from_slice(&vformat);
- let vci = NACodecTypeInfo::Video(NAVideoInfo::new(width, height, false, YUV420_FORMAT));
+ let fmt = match video_codec {
+ 600 => PAL8_FORMAT,
+ 601 => RGB565_FORMAT,
+ _ => YUV420_FORMAT,
+ };
+
+ let vci = NACodecTypeInfo::Video(NAVideoInfo::new(width, height, false, fmt));
let vinfo = NACodecInfo::new(codec_name, vci, Some(edata));
let ret = strmgr.add_stream(NAStream::new(StreamType::Video, stream_id, vinfo, tb_num, tb_den, (frm_per_chunk * num_chunks) as u64));
if ret.is_some() {
for ((&id, &sratestr), (&chan, &fmt)) in sound_ids.iter().zip(srates.iter())
.zip(channels.iter().zip(sndformats.iter())) {
let codec_id = parse_uint(id)?;
- let codec_name = if codec_id == 1 { "pcm" } else { "unknown" };
let channels = parse_uint(chan)?;
validate!(channels > 0 && channels < 16);
+ let edata = fmt.to_owned();
let bits = parse_uint(fmt)?;
+ let codec_name = match codec_id {
+ 1 => "arm_rawaudio",
+ 101 if bits == 8 && video_codec != 122 => "arm_rawaudio",
+ 101 => "escape-adpcm",
+ _ => "unknown"
+ };
let mut srate = parse_uint(sratestr)?;
if srate > 0 && srate < 1000 { // probably in microseconds instead of Hertz
srate = 1000000 / srate;
let fmt = if bits == 8 { SND_U8_FORMAT } else { SND_S16_FORMAT };
let aci = NACodecTypeInfo::Audio(NAAudioInfo::new(srate, channels as u8, fmt, 0));
- let ainfo = NACodecInfo::new(codec_name, aci, None);
+ let ainfo = NACodecInfo::new(codec_name, aci, Some(edata));
let ret = strmgr.add_stream(NAStream::new(StreamType::Audio, stream_id, ainfo, 1, srate, 0));
if let Some(id) = ret {
self.audio_ids.push(id);
}
fn get_data(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NARawData> {
+ #[cfg(feature="demuxer_tca")]
+ if let Some(ref mut tca) = self.tca {
+ return tca.get_frame_raw(self.src, strmgr);
+ }
+
while self.cur_chunk < self.chunk_offs.len() {
let chunk = &self.chunk_offs[self.cur_chunk];
match self.state {
let mut si = SeekIndex::new();
dmx.open(&mut sm, &mut si).unwrap();
+ loop {
+ let pktres = dmx.get_data(&mut sm);
+ if let Err(e) = pktres {
+ if e == DemuxerError::EOF { break; }
+ panic!("error");
+ }
+ let pkt = pktres.unwrap();
+ println!("Got {}", pkt);
+ }
+ }
+ #[test]
+ fn test_armovie_tca_demux() {
+ // a sample from All About Planes
+ let mut file = File::open("assets/Acorn/wessex").unwrap();
+ let mut fr = FileReader::new_read(&mut file);
+ let mut br = ByteReader::new(&mut fr);
+ let mut dmx = ARMovieDemuxer::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_data(&mut sm);
if let Err(e) = pktres {