initial seeking support
[nihav.git] / nihav-commonfmt / src / demuxers / avi.rs
index da941b3f40c76de78c070a631d3d0878c3da99d9..6603b5705a1f32691378eacb4bfcad0004e48171 100644 (file)
@@ -41,6 +41,8 @@ struct AVIDemuxer<'a> {
     num_streams:    u8,
     size:           usize,
     movi_size:      usize,
+    movi_pos:       u64,
+    movi_orig:      usize,
     sstate:         StreamState,
     tb_num:         u32,
     tb_den:         u32,
@@ -59,7 +61,7 @@ struct RIFFParser {
 
 impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
     #[allow(unused_variables)]
-    fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
+    fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
         self.read_header(strmgr)?;
         Ok(())
     }
@@ -87,12 +89,15 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
                 if self.movi_size == 0 { return Err(EOF); }
                 continue;
             }
+            if tag[0] == b'i' && tag[1] == b'x' {
+                return Err(EOF);
+            }
             if tag[0] < b'0' || tag[0] > b'9' || tag[1] < b'0' || tag[1] > b'9' {
                 return Err(InvalidData);
             }
             let stream_no = (tag[0] - b'0') * 10 + (tag[1] - b'0');
             let str = strmgr.get_stream(stream_no as usize);
-            if let None = str { return Err(InvalidData); }
+            if str.is_none() { return Err(InvalidData); }
             let stream = str.unwrap();
             if size == 0 {
                 self.movi_size -= 8;
@@ -109,9 +114,21 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
         }
     }
 
-    #[allow(unused_variables)]
-    fn seek(&mut self, time: u64) -> DemuxerResult<()> {
-        Err(NotImplemented)
+    fn seek(&mut self, time: u64, seek_index: &SeekIndex) -> DemuxerResult<()> {
+        let ret = seek_index.find_pos(time);
+        if ret.is_none() {
+            return Err(DemuxerError::SeekError);
+        }
+        let pos = ret.unwrap().pos;
+        self.src.seek(SeekFrom::Start(pos))?;
+
+        let cur_pos = self.src.tell();
+        if cur_pos < self.movi_pos { return Err(DemuxerError::SeekError); }
+        let skip_size = (cur_pos - self.movi_pos) as usize;
+        if skip_size > self.movi_size { return Err(DemuxerError::SeekError); }
+        self.movi_size = self.movi_orig - skip_size;
+
+        Ok(())
     }
 }
 
@@ -123,6 +140,8 @@ impl<'a> AVIDemuxer<'a> {
             src: io,
             size: 0,
             movi_size: 0,
+            movi_pos:  0,
+            movi_orig: 0,
             sstate: StreamState::new(),
             tb_num: 0,
             tb_den: 0,
@@ -145,26 +164,24 @@ impl<'a> AVIDemuxer<'a> {
             return Ok((size, true));
         }
 
-        for i in 0..CHUNKS.len() {
-            if RIFFTag::Chunk(tag) == CHUNKS[i].tag {
-                let psize = (CHUNKS[i].parse)(self, strmgr, size)?;
+        for chunk in CHUNKS.iter() {
+            if RIFFTag::Chunk(tag) == chunk.tag {
+                let psize = (chunk.parse)(self, strmgr, size)?;
                 if psize != size { return Err(InvalidData); }
                 if (psize & 1) == 1 { self.src.read_skip(1)?; }
                 return Ok((size + 8, false));
             }
-            if RIFFTag::List(tag, ltag) == CHUNKS[i].tag {
+            if RIFFTag::List(tag, ltag) == chunk.tag {
                 let mut rest_size = size - 4;
-                let psize = (CHUNKS[i].parse)(self, strmgr, rest_size)?;
+                let psize = (chunk.parse)(self, strmgr, rest_size)?;
                 if psize > rest_size { return Err(InvalidData); }
                 rest_size -= psize;
                 while rest_size > 0 {
                     let (psize, _) = self.parse_chunk(strmgr, end_tag, rest_size, depth+1)?;
                     if psize > rest_size { return Err(InvalidData); }
                     rest_size -= psize;
-                    if (psize & 1) == 1 {
-                        if rest_size > 0 {
-                            rest_size -= 1;
-                        }
+                    if ((psize & 1) == 1) && (rest_size > 0) {
+                        rest_size -= 1;
                     }
                 }
 
@@ -178,23 +195,36 @@ impl<'a> AVIDemuxer<'a> {
             self.src.read_skip(size - 4)?;
         }
         if (size & 1) == 1 { self.src.read_skip(1)?; }
-        return Ok((size + 8, false));
+        Ok((size + 8, false))
     }
 
     fn read_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
         let riff_tag = self.src.read_u32be()?;
         let size     = self.src.read_u32le()? as usize;
         let avi_tag  = self.src.read_u32be()?;
-        if riff_tag != mktag!(b"RIFF") || avi_tag != mktag!(b"AVI ") {
+        let mut matches = false;
+        for rt in RIFF_TAGS.iter() {
+            if rt[0] == riff_tag && rt[1] == avi_tag {
+                matches = true;
+                break;
+            }
+        }
+        if !matches {
             return Err(InvalidData);
         }
         self.size = size;
         let mut rest_size = size;
         loop {
             let (csz, end) = self.parse_chunk(strmgr, RIFFTag::List(mktag!(b"LIST"), mktag!(b"movi")), rest_size,0)?;
-            if end { self.movi_size = csz - 4; break; }
+            if end {
+                self.movi_size = csz - 4;
+                self.movi_orig = self.movi_size;
+                self.movi_pos = self.src.tell();
+                break;
+            }
             rest_size -= csz;
         }
+//todo read index
         if !self.sstate.valid_state() || self.sstate.strm_no != self.num_streams {
             return Err(InvalidData);
         }
@@ -203,25 +233,31 @@ impl<'a> AVIDemuxer<'a> {
 
     fn read_extradata(&mut self, size: usize) -> DemuxerResult<Option<Vec<u8>>> {
         if size == 0 { return Ok(None); }
-        let mut edvec: Vec<u8> = Vec::with_capacity(size);
-        edvec.resize(size, 0);
+        let mut edvec: Vec<u8> = vec![0; size];
         self.src.read_buf(&mut edvec)?;
         Ok(Some(edvec))
     }
 }
 
-const CHUNKS: [RIFFParser; 6] = [
+const RIFF_TAGS: &[[u32; 2]] = &[
+    [ mktag!(b"RIFF"), mktag!(b"AVI ") ],
+    [ mktag!(b"RIFF"), mktag!(b"AVIX") ],
+    [ mktag!(b"ON2 "), mktag!(b"ON2f") ],
+];
+
+const CHUNKS: [RIFFParser; 7] = [
     RIFFParser { tag: RIFFTag::List(mktag!(b"LIST"), mktag!(b"hdrl")), parse: parse_hdrl },
     RIFFParser { tag: RIFFTag::List(mktag!(b"LIST"), mktag!(b"strl")), parse: parse_strl },
     RIFFParser { tag: RIFFTag::Chunk(mktag!(b"avih")), parse: parse_avih },
+    RIFFParser { tag: RIFFTag::Chunk(mktag!(b"ON2h")), parse: parse_avih },
     RIFFParser { tag: RIFFTag::Chunk(mktag!(b"strf")), parse: parse_strf },
     RIFFParser { tag: RIFFTag::Chunk(mktag!(b"strh")), parse: parse_strh },
     RIFFParser { tag: RIFFTag::Chunk(mktag!(b"JUNK")), parse: parse_junk },
 ];
 
 fn is_list_tag(tag: u32) -> bool {
-    for i in 0..CHUNKS.len() {
-        if let RIFFTag::List(ltag, _) = CHUNKS[i].tag {
+    for chunk in CHUNKS.iter() {
+        if let RIFFTag::List(ltag, _) = chunk.tag {
             if tag == ltag {
                 return true;
             }
@@ -279,7 +315,7 @@ fn parse_strh(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) ->
 }
 
 fn parse_strf(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult<usize> {
-    if let None = dmx.sstate.strm_type { return Err(InvalidData); }
+    if dmx.sstate.strm_type.is_none() { return Err(InvalidData); }
     match dmx.sstate.strm_type.unwrap() {
         StreamType::Video    => parse_strf_vids(dmx, strmgr, size),
         StreamType::Audio    => parse_strf_auds(dmx, strmgr, size),
@@ -314,8 +350,8 @@ fn parse_strf_vids(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize
                     Some(name) => name,
                 };
     let vinfo = NACodecInfo::new(cname, vci, edata);
-    let res = strmgr.add_stream(NAStream::new(StreamType::Video, dmx.sstate.strm_no as u32, vinfo, dmx.tb_num, dmx.tb_den));
-    if let None = res { return Err(MemoryError); }
+    let res = strmgr.add_stream(NAStream::new(StreamType::Video, u32::from(dmx.sstate.strm_no), vinfo, dmx.tb_num, dmx.tb_den));
+    if res.is_none() { return Err(MemoryError); }
     dmx.sstate.reset();
     Ok(size)
 }
@@ -338,8 +374,8 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize
                     Some(name) => name,
                 };
     let ainfo = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata);
-    let res = strmgr.add_stream(NAStream::new(StreamType::Audio, dmx.sstate.strm_no as u32, ainfo, dmx.tb_num, dmx.tb_den));
-    if let None = res { return Err(MemoryError); }
+    let res = strmgr.add_stream(NAStream::new(StreamType::Audio, u32::from(dmx.sstate.strm_no), ainfo, dmx.tb_num, dmx.tb_den));
+    if res.is_none() { return Err(MemoryError); }
     dmx.sstate.reset();
     Ok(size)
 }
@@ -347,8 +383,8 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize
 fn parse_strf_xxxx(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult<usize> {
     let edata = dmx.read_extradata(size)?;
     let info = NACodecInfo::new("unknown", NACodecTypeInfo::None, edata);
-    let res = strmgr.add_stream(NAStream::new(StreamType::Data, dmx.sstate.strm_no as u32, info, dmx.tb_num, dmx.tb_den));
-    if let None = res { return Err(MemoryError); }
+    let res = strmgr.add_stream(NAStream::new(StreamType::Data, u32::from(dmx.sstate.strm_no), info, dmx.tb_num, dmx.tb_den));
+    if res.is_none() { return Err(MemoryError); }
     dmx.sstate.reset();
     Ok(size)
 }
@@ -385,7 +421,7 @@ fn parse_junk(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) ->
 pub struct AVIDemuxerCreator { }
 
 impl DemuxerCreator for AVIDemuxerCreator {
-    fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<DemuxCore<'a> + 'a> {
+    fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
         Box::new(AVIDemuxer::new(br))
     }
     fn get_name(&self) -> &'static str { "avi" }
@@ -398,7 +434,7 @@ mod test {
 
     #[test]
     fn test_avi_demux() {
-        let mut file = File::open("assets/laser05.avi").unwrap();
+        let mut file = File::open("assets/Indeo/laser05.avi").unwrap();
         let mut fr = FileReader::new_read(&mut file);
         let mut br = ByteReader::new(&mut fr);
         let mut dmx = AVIDemuxer::new(&mut br);