]> git.nihav.org Git - nihav.git/blobdiff - nihav-acorn/src/demuxers/armovie.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-acorn / src / demuxers / armovie.rs
index 9b9d8ee4c2f2db636101ee174577cf81af09a457..23cf94abe4a5dc7bec4c23e33f0a0559a5542451 100644 (file)
@@ -1,5 +1,8 @@
 use nihav_core::demuxers::*;
 
+#[cfg(feature="demuxer_tca")]
+use super::tca::TCACoreDemuxer;
+
 const VIDEO_CODECS: &[(i32, &str)] = &[
     (  1, "movinglines"),
     (  2, "arm_rawvideo"),
@@ -13,6 +16,10 @@ const VIDEO_CODECS: &[(i32, &str)] = &[
     (122, "escape122"),
     (124, "escape124"),
     (130, "escape130"),
+    (500, "euclid"),
+    (600, "msvideo1"),
+    (601, "msvideo1"),
+    (602, "cinepak"),
     (800, "linepack"),
     (802, "movie16_3"),
 ];
@@ -26,7 +33,7 @@ impl<'a> ReadString for ByteReader<'a> {
         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);
@@ -152,6 +159,8 @@ struct ARMovieDemuxer<'a> {
     state:          ReadState,
     video_id:       Option<usize>,
     audio_ids:      Vec<usize>,
+    #[cfg(feature="demuxer_tca")]
+    tca:            Option<TCACoreDemuxer>,
 }
 
 impl<'a> ARMovieDemuxer<'a> {
@@ -163,6 +172,8 @@ 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<()> {
@@ -192,7 +203,7 @@ impl<'a> ARMovieDemuxer<'a> {
                 }
 
                 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);
@@ -218,7 +229,7 @@ impl<'a> RawDemuxCore<'a> for ARMovieDemuxer<'a> {
         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()?;
@@ -259,6 +270,24 @@ impl<'a> RawDemuxCore<'a> for ARMovieDemuxer<'a> {
 
         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) {
@@ -278,7 +307,13 @@ impl<'a> RawDemuxCore<'a> for ARMovieDemuxer<'a> {
             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() {
@@ -296,10 +331,16 @@ impl<'a> RawDemuxCore<'a> for ARMovieDemuxer<'a> {
             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;
@@ -308,7 +349,7 @@ impl<'a> RawDemuxCore<'a> for ARMovieDemuxer<'a> {
                 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);
@@ -323,6 +364,11 @@ impl<'a> RawDemuxCore<'a> for ARMovieDemuxer<'a> {
     }
 
     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 {
@@ -407,6 +453,27 @@ mod test {
         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 {