avi: support raw YUV formats
[nihav.git] / nihav-commonfmt / src / demuxers / avi.rs
index 511a22f7284fbc18a5ca6eb7a1750bc06d2989c6..73bd02f9731139c93f08fa270dec22c7bceb6a3c 100644 (file)
@@ -1,6 +1,7 @@
 use nihav_core::demuxers::*;
-use nihav_core::register;
+use nihav_registry::register;
 use nihav_core::demuxers::DemuxerError::*;
+use std::str::FromStr;
 
 macro_rules! mktag {
     ($a:expr, $b:expr, $c:expr, $d:expr) => ({
@@ -34,6 +35,12 @@ impl StreamState {
     }
 }
 
+struct PalInfo {
+    pal:        Arc<[u8; 1024]>,
+    changed:    bool,
+    stream_no:  usize,
+}
+
 #[allow(dead_code)]
 struct AVIDemuxer<'a> {
     src:            &'a mut ByteReader<'a>,
@@ -41,9 +48,14 @@ 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,
+    strm_duration:  u32,
+    key_offs:       Vec<u64>,
+    pal:            Vec<PalInfo>,
 }
 
 #[derive(Debug,Clone,Copy,PartialEq)]
@@ -58,9 +70,8 @@ struct RIFFParser {
 }
 
 impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
-    #[allow(unused_variables)]
-    fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
-        self.read_header(strmgr)?;
+    fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+        self.read_header(strmgr, seek_index)?;
         Ok(())
     }
 
@@ -73,6 +84,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") {
@@ -87,12 +99,21 @@ 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') || (&tag == b"idx1") {
+                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');
+            if tag[2] == b'p' && tag[3] == b'c' {
+                self.parse_palette_change(stream_no as usize, size)?;
+                self.movi_size -= size;
+                if self.movi_size == 0 { return Err(EOF); }
+                continue;
+            }
             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;
@@ -100,8 +121,18 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
                 continue;
             }
             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 mut ts = NATimeInfo::new(Some(self.cur_frame[stream_no as usize]), None, None, tb_num, tb_den);
+            if stream.get_media_type() == StreamType::Audio && tb_num == 1 && stream.get_info().get_name() == "pcm" {
+                ts.pts = None;
+            }
+            let mut pkt = self.src.read_packet(stream, ts, is_keyframe, size)?;
+            for pe in self.pal.iter_mut() {
+                if pe.stream_no == (stream_no as usize) {
+                    pkt.add_side_data(NASideData::Palette(pe.changed, pe.pal.clone()));
+                    pe.changed = false;
+                    break;
+                }
+            }
             self.cur_frame[stream_no as usize] += 1;
             self.movi_size -= size + 8;
 
@@ -109,10 +140,30 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
         }
     }
 
-    #[allow(unused_variables)]
-    fn seek(&mut self, time: u64) -> DemuxerResult<()> {
-        Err(NotImplemented)
+    fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+        let ret = seek_index.find_pos(time);
+        if ret.is_none() {
+            return Err(DemuxerError::SeekError);
+        }
+        let seek_info = ret.unwrap();
+
+        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(())
     }
+    fn get_duration(&self) -> u64 { 0 }
+}
+
+impl<'a> NAOptionHandler for AVIDemuxer<'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> AVIDemuxer<'a> {
@@ -123,9 +174,14 @@ 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,
+            strm_duration: 0,
+            key_offs: Vec::new(),
+            pal: Vec::new(),
         }
     }
 
@@ -145,26 +201,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 +232,53 @@ 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<()> {
+    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()?;
-        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;
         }
+        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);
         }
@@ -203,25 +287,56 @@ 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))
     }
+
+    fn parse_palette_change(&mut self, stream_no: usize, size: usize) -> DemuxerResult<()> {
+        for pe in self.pal.iter_mut() {
+            if pe.stream_no == stream_no {
+                let start_clr           = self.src.read_byte()? as usize;
+                let len                 = self.src.read_byte()? as usize;
+                let _flags              = self.src.read_u16le()?;
+                validate!(start_clr + len <= 256);
+                validate!(len * 4 + 4 == size);
+                let mut newpal = *pe.pal;
+                for i in start_clr..(start_clr + len) {
+                    newpal[i * 4]       = self.src.read_byte()?;
+                    newpal[i * 4 + 1]   = self.src.read_byte()?;
+                    newpal[i * 4 + 2]   = self.src.read_byte()?;
+                    newpal[i * 4 + 3]   = 0;
+                                          self.src.read_byte()?; // flags
+                }
+                pe.pal = Arc::new(newpal);
+                pe.changed = true;
+                return Ok(());
+            }
+        }
+        self.src.read_skip(size)?;
+        Ok(())
+    }
 }
 
-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;
             }
@@ -252,7 +367,7 @@ fn parse_strh(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) ->
     dmx.tb_num = dmx.src.read_u32le()?; //scale
     dmx.tb_den = dmx.src.read_u32le()?; //rate
     dmx.src.read_skip(4)?; //start
-    dmx.src.read_skip(4)?; //length
+    dmx.strm_duration = dmx.src.read_u32le()?;
     dmx.src.read_skip(4)?; //buf size
     dmx.src.read_skip(4)?; //quality
     dmx.src.read_skip(4)?; //sample size
@@ -279,7 +394,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),
@@ -291,7 +406,7 @@ fn parse_strf(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) ->
 fn parse_strf_vids(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult<usize> {
     if size < 40 { return Err(InvalidData); }
     let bi_size         = dmx.src.read_u32le()?;
-    if (bi_size as usize) > size { return Err(InvalidData); }
+    if (bi_size as usize) < 40 { return Err(InvalidData); }
     let width           = dmx.src.read_u32le()?;
     let height          = dmx.src.read_u32le()? as i32;
     let planes          = dmx.src.read_u16le()?;
@@ -302,24 +417,89 @@ fn parse_strf_vids(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize
     let xdpi            = dmx.src.read_u32le()?;
     let ydpi            = dmx.src.read_u32le()?;
     let colors          = dmx.src.read_u32le()?;
+    validate!(colors <= 256);
     let imp_colors      = dmx.src.read_u32le()?;
 
     let flip = height < 0;
     let format = if bitcount > 8 { RGB24_FORMAT } else { PAL8_FORMAT };
-    let vhdr = NAVideoInfo::new(width as usize, if flip { -height as usize } else { height as usize}, flip, PAL8_FORMAT);
+    let mut vhdr = NAVideoInfo::new(width as usize, if flip { -height as usize } else { height as usize}, flip, format);
+    vhdr.bits = (planes as u8) * (bitcount as u8);
+    let cname = if find_raw_rgb_fmt(&compression, planes, bitcount, flip, &mut vhdr) {
+            "rawvideo-ms"
+        } else if find_raw_yuv_fmt(&compression, &mut vhdr) {
+            "rawvideo"
+        } else {
+            match register::find_codec_from_avi_fourcc(&compression) {
+                None => "unknown",
+                Some(name) => name,
+            }
+        };
     let vci = NACodecTypeInfo::Video(vhdr);
     let edata = dmx.read_extradata(size - 40)?;
-    let cname = match register::find_codec_from_avi_fourcc(&compression) {
-                    None => "unknown",
-                    Some(name) => name,
-                };
+    if colors > 0 {
+        if let Some(ref buf) = edata {
+            let mut pal = [0u8; 1024];
+            for (dpal, spal) in pal.chunks_mut(4).take(colors as usize).zip(buf.chunks(4)) {
+                dpal[0] = spal[2];
+                dpal[1] = spal[1];
+                dpal[2] = spal[0];
+                dpal[3] = 0;
+            }
+            let pal = PalInfo { pal: Arc::new(pal), changed: true, stream_no: strmgr.get_num_streams() };
+            dmx.pal.push(pal);
+        }
+    }
     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, u64::from(dmx.strm_duration)));
+    if res.is_none() { return Err(MemoryError); }
     dmx.sstate.reset();
     Ok(size)
 }
 
+fn find_raw_rgb_fmt(compr: &[u8; 4], planes: u16, bitcount: u16, flip: bool, vhdr: &mut NAVideoInfo) -> bool {
+    match compr {
+        &[0, 0, 0, 0] | b"DIB " => {
+            if planes != 1 {
+                return false;
+            }
+            let fmt_name = match bitcount {
+                     8 => "pal8",
+                    16 => "bgr555",
+                    24 => "bgr24",
+                    32 => "bgra24",
+                    _ => return false,
+                };
+            if let Ok(fmt) = NAPixelFormaton::from_str(fmt_name) {
+                vhdr.format = fmt;
+                vhdr.flipped = !flip;
+                true
+            } else {
+                false
+            }
+        },
+        _ => false,
+    }
+}
+
+fn find_raw_yuv_fmt(compr: &[u8; 4], vhdr: &mut NAVideoInfo) -> bool {
+    let (fmt_name, swapuv) = match compr {
+            b"UYVY" | b"UYNY" | b"UYNV" | b"2vuy" => ("uyvy", false),
+            b"I420" | b"IYUV" => ("yuv420p", false),
+            b"YV12" => ("yuv420p", true),
+            b"YVU9" => ("yuv410p", true),
+            _ => return false,
+        };
+    if let Ok(fmt) = NAPixelFormaton::from_str(fmt_name) {
+        vhdr.format = fmt;
+        if swapuv {
+            vhdr.format.comp_info.swap(1, 2);
+        }
+        true
+    } else {
+        false
+    }
+}
+
 #[allow(unused_variables)]
 fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult<usize> {
     if size < 16 { return Err(InvalidData); }
@@ -328,18 +508,25 @@ 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 signed = bits_per_sample > 8;
+    let soniton = NASoniton::new(bits_per_sample as u8, if signed { SONITON_FLAG_SIGNED } else { 0 });
     let ahdr = NAAudioInfo::new(samplespersec, channels as u8, soniton, block_align as usize);
-    let edata = dmx.read_extradata(size - 16)?;
+    let edata = if size > 16 {
+            let edata_size  = dmx.src.read_u16le()? as usize;
+            validate!(edata_size + 18 <= size);
+            dmx.read_extradata(size - 18)?
+        } else {
+            None
+        };
     let cname = match register::find_codec_from_wav_twocc(w_format_tag) {
                     None => "unknown",
                     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, u64::from(dmx.strm_duration)));
+    if res.is_none() { return Err(MemoryError); }
     dmx.sstate.reset();
     Ok(size)
 }
@@ -347,8 +534,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, u64::from(dmx.strm_duration)));
+    if res.is_none() { return Err(MemoryError); }
     dmx.sstate.reset();
     Ok(size)
 }
@@ -382,6 +569,50 @@ fn parse_junk(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) ->
     Ok(size)
 }
 
+#[allow(clippy::verbose_bit_mask)]
+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];
+    let mut add_offset = 0;
+    let mut set_offset = false;
+    for _ in 0..num_entries {
+                              src.read_buf(&mut tag)?;
+        let flags           = src.read_u32le()?;
+        let mut offset      = src.read_u32le()? as u64;
+        let _length         = src.read_u32le()?;
+
+        if !set_offset && offset < movi_pos {
+            add_offset = movi_pos - offset;
+        }
+        set_offset = true;
+
+        offset += add_offset;
+
+        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);
+                    validate!(offset >= movi_pos);
+                    seek_idx.add_entry(stream_no as u32, SeekEntry { time, pts, pos: offset });
+                }
+                key_offs.push(offset);
+            }
+        }
+        counter[stream_no] += 1;
+    }
+    key_offs.sort_unstable();
+    Ok(size)
+}
+
 pub struct AVIDemuxerCreator { }
 
 impl DemuxerCreator for AVIDemuxerCreator {
@@ -403,7 +634,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);