avi demuxer: mark packets as keyframe if we have index
[nihav.git] / nihav-commonfmt / src / demuxers / avi.rs
index 6603b5705a1f32691378eacb4bfcad0004e48171..62ff8aac747ef85d5772de618ebd6d5c6514be89 100644 (file)
@@ -1,5 +1,5 @@
 use nihav_core::demuxers::*;
-use nihav_core::register;
+use nihav_registry::register;
 use nihav_core::demuxers::DemuxerError::*;
 
 macro_rules! mktag {
@@ -46,6 +46,7 @@ struct AVIDemuxer<'a> {
     sstate:         StreamState,
     tb_num:         u32,
     tb_den:         u32,
+    key_offs:       Vec<u64>,
 }
 
 #[derive(Debug,Clone,Copy,PartialEq)]
@@ -60,9 +61,8 @@ struct RIFFParser {
 }
 
 impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
-    #[allow(unused_variables)]
     fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
-        self.read_header(strmgr)?;
+        self.read_header(strmgr, seek_index)?;
         Ok(())
     }
 
@@ -75,6 +75,7 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
                 self.movi_size -= 1;
                 if self.movi_size == 0 { return Err(EOF); }
             }
+            let is_keyframe = self.key_offs.binary_search(&self.src.tell()).is_ok();
             self.src.read_buf(&mut tag)?;
             let size = self.src.read_u32le()? as usize;
             if mktag!(tag) == mktag!(b"JUNK") {
@@ -106,7 +107,7 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
             }
             let (tb_num, tb_den) = stream.get_timebase();
             let ts = NATimeInfo::new(Some(self.cur_frame[stream_no as usize]), None, None, tb_num, tb_den);
-            let pkt = self.src.read_packet(stream, ts, false, size)?;
+            let pkt = self.src.read_packet(stream, ts, is_keyframe, size)?;
             self.cur_frame[stream_no as usize] += 1;
             self.movi_size -= size + 8;
 
@@ -119,15 +120,16 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
         if ret.is_none() {
             return Err(DemuxerError::SeekError);
         }
-        let pos = ret.unwrap().pos;
-        self.src.seek(SeekFrom::Start(pos))?;
+        let seek_info = ret.unwrap();
 
-        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 seek_info.pos < self.movi_pos { return Err(DemuxerError::SeekError); }
+        let skip_size = (seek_info.pos - self.movi_pos) as usize;
         if skip_size > self.movi_size { return Err(DemuxerError::SeekError); }
         self.movi_size = self.movi_orig - skip_size;
 
+        self.cur_frame[seek_info.str_id as usize] = seek_info.pts;
+        self.src.seek(SeekFrom::Start(seek_info.pos))?;
+
         Ok(())
     }
 }
@@ -145,6 +147,7 @@ impl<'a> AVIDemuxer<'a> {
             sstate: StreamState::new(),
             tb_num: 0,
             tb_den: 0,
+            key_offs: Vec::new(),
         }
     }
 
@@ -198,7 +201,7 @@ impl<'a> AVIDemuxer<'a> {
         Ok((size + 8, false))
     }
 
-    fn read_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
+    fn read_header(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult<()> {
         let riff_tag = self.src.read_u32be()?;
         let size     = self.src.read_u32le()? as usize;
         let avi_tag  = self.src.read_u32be()?;
@@ -224,7 +227,24 @@ impl<'a> AVIDemuxer<'a> {
             }
             rest_size -= csz;
         }
-//todo read index
+        if !seek_idx.skip_index {
+            self.src.read_skip(self.movi_size)?;
+            while rest_size > 0 {
+                let ret = self.parse_chunk(strmgr, RIFFTag::Chunk(mktag!(b"idx1")), rest_size,0);
+                if ret.is_err() { break; }
+                let (csz, end) = ret.unwrap();
+                if end {
+                    let _res = parse_idx1(&mut self.src, strmgr, seek_idx, csz, self.movi_pos, &mut self.key_offs);
+                    break;
+                }
+                rest_size -= csz;
+            }
+        }
+        if self.movi_pos != 0 {
+            self.src.seek(SeekFrom::Start(self.movi_pos))?;
+        } else {
+            return Err(InvalidData);
+        }
         if !self.sstate.valid_state() || self.sstate.strm_no != self.num_streams {
             return Err(InvalidData);
         }
@@ -364,7 +384,7 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize
     let samplespersec       = dmx.src.read_u32le()?;
     let avgbytespersec      = dmx.src.read_u32le()?;
     let block_align         = dmx.src.read_u16le()?;
-    let bits_per_sample     = dmx.src.read_u16le()? * 8;
+    let bits_per_sample     = dmx.src.read_u16le()?;
 
     let soniton = NASoniton::new(bits_per_sample as u8, SONITON_FLAG_SIGNED);
     let ahdr = NAAudioInfo::new(samplespersec, channels as u8, soniton, block_align as usize);
@@ -418,6 +438,39 @@ fn parse_junk(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) ->
     Ok(size)
 }
 
+fn parse_idx1(src: &mut ByteReader, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex, size: usize, movi_pos: u64, key_offs: &mut Vec<u64>) -> DemuxerResult<usize> {
+    validate!((size & 15) == 0);
+    let mut tag = [0u8; 4];
+    let num_entries = size >> 4;
+    let mut counter = [0u64; 100];
+    for _ in 0..num_entries {
+                              src.read_buf(&mut tag)?;
+        let flags           = src.read_u32le()?;
+        let offset          = src.read_u32le()? as u64;
+        let _length         = src.read_u32le()?;
+
+        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')) as usize;
+
+        if (flags & 0x10) != 0 {
+            if let Some(str) = strmgr.get_stream(stream_no) {
+                if str.get_media_type() == StreamType::Video {
+                    let (tb_num, tb_den) = str.get_timebase();
+                    let pts = counter[stream_no];
+                    let time = NATimeInfo::ts_to_time(pts, 1000, tb_num, tb_den);
+                    seek_idx.add_entry(stream_no as u32, SeekEntry { time, pts, pos: offset + movi_pos - 4 });
+                }
+                key_offs.push(offset);
+            }
+        }
+        counter[stream_no] += 1;
+    }
+    key_offs.sort_unstable();
+    Ok(size)
+}
+
 pub struct AVIDemuxerCreator { }
 
 impl DemuxerCreator for AVIDemuxerCreator {
@@ -439,7 +492,8 @@ mod test {
         let mut br = ByteReader::new(&mut fr);
         let mut dmx = AVIDemuxer::new(&mut br);
         let mut sm = StreamManager::new();
-        dmx.open(&mut sm).unwrap();
+        let mut si = SeekIndex::new();
+        dmx.open(&mut sm, &mut si).unwrap();
 
         loop {
             let pktres = dmx.get_frame(&mut sm);