]> git.nihav.org Git - nihav.git/blobdiff - nihav-commonfmt/src/demuxers/avi.rs
avi: fix handling of multiple palette changes in single 'pc' chunk
[nihav.git] / nihav-commonfmt / src / demuxers / avi.rs
index 2b8958087906599e0cd5572efb6a9c574e7f0e0a..113f9e050fa3198537340a9ce616ebb114c20739 100644 (file)
@@ -140,11 +140,16 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
                 continue;
             }
             if (tag[0] == b'i' && tag[1] == b'x') || (&tag == b"idx1") {
+                let idx_pos = self.src.tell() - 8;
                 if !self.odml {
                     return Err(EOF);
                 }
                 self.src.read_skip(size)?;
-                self.try_next_odml_chunk()?;
+                if idx_pos > self.movi_pos {
+                    self.try_next_odml_chunk()?;
+                } else {
+                    self.movi_pos = self.src.tell();
+                }
                 continue;
             }
             if tag[0] < b'0' || tag[0] > b'9' || tag[1] < b'0' || tag[1] > b'9' {
@@ -162,9 +167,13 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
                 }
                 continue;
             }
-            let str = strmgr.get_stream(stream_no as usize);
-            if str.is_none() { return Err(InvalidData); }
-            let stream = str.unwrap();
+            let stream = strmgr.get_stream(stream_no as usize);
+            if stream.is_none() {
+                self.src.read_skip(size)?;
+                self.movi_size -= size + 8;
+                continue;
+            }
+            let stream = stream.unwrap();
             if size == 0 {
                 self.movi_size -= 8;
                 if self.movi_size == 0 {
@@ -175,8 +184,8 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
                 }
                 continue;
             }
-            let (tb_num, tb_den) = stream.get_timebase();
-            let mut ts = NATimeInfo::new(Some(self.cur_frame[stream_no as usize]), None, None, tb_num, tb_den);
+            let (tb_num, _) = stream.get_timebase();
+            let mut ts = stream.make_ts(Some(self.cur_frame[stream_no as usize]), None, None);
             if stream.get_media_type() == StreamType::Audio && tb_num == 1 && stream.get_info().get_name() == "pcm" {
                 ts.pts = None;
             }
@@ -234,7 +243,7 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> {
         }
         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); }
+        if skip_size > self.movi_orig { return Err(DemuxerError::SeekError); }
         self.movi_size = self.movi_orig - skip_size;
 
         self.cur_frame[seek_info.str_id as usize] = seek_info.pts;
@@ -418,18 +427,25 @@ impl<'a> AVIDemuxer<'a> {
     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;
+                let mut data_left = size;
+                while data_left > 0 {
+                    validate!(data_left >= 8);
+                    let start_clr       = self.src.read_byte()? as usize;
+                    let len             = self.src.read_byte()? as usize;
+                    let len = if len == 0 { 256 } else { len };
+                    let _flags          = self.src.read_u16le()?;
+                    validate!(start_clr + len <= 256);
+                    let change_size = len * 4 + 4;
+                    validate!(change_size <= data_left);
+                    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
+                    }
+                    data_left -= change_size;
                 }
                 pe.pal = Arc::new(newpal);
                 pe.changed = true;
@@ -493,6 +509,7 @@ const CHUNKS: &[RIFFParser] = &[
     RIFFParser { tag: RIFFTag::Chunk(mktag!(b"indx")), parse: parse_indx },
     RIFFParser { tag: RIFFTag::Chunk(mktag!(b"JUNK")), parse: parse_junk },
     RIFFParser { tag: RIFFTag::List(mktag!(b"LIST"), mktag!(b"odml")), parse: parse_odml },
+    RIFFParser { tag: RIFFTag::List(mktag!(b"LIST"), mktag!(b"rec ")), parse: parse_rec },
 ];
 
 fn is_list_tag(tag: u32) -> bool {
@@ -521,6 +538,10 @@ fn parse_odml(dmx: &mut AVIDemuxer, _strmgr: &mut StreamManager, _size: usize) -
     Ok(0)
 }
 
+fn parse_rec(_dmx: &mut AVIDemuxer, _strmgr: &mut StreamManager, _size: usize) -> DemuxerResult<usize> {
+    Ok(0)
+}
+
 #[allow(unused_variables)]
 fn parse_strh(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult<usize> {
     if size < 0x38 { return Err(InvalidData); }
@@ -782,14 +803,14 @@ fn parse_idx1(src: &mut ByteReader, strmgr: &mut StreamManager, seek_idx: &mut S
         offset += add_offset;
 
         if tag[0] < b'0' || tag[0] > b'9' || tag[1] < b'0' || tag[1] > b'9' {
-            return Err(InvalidData);
+            continue;
         }
         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();
+            if let Some(stream) = strmgr.get_stream(stream_no) {
+                if stream.get_media_type() == StreamType::Video {
+                    let (tb_num, tb_den) = stream.get_timebase();
                     let pts = counter[stream_no];
                     let time = NATimeInfo::ts_to_time(pts, 1000, tb_num, tb_den);
                     validate!(offset >= movi_pos);
@@ -814,7 +835,7 @@ fn parse_odml_ix(src: &mut ByteReader, strmgr: &mut StreamManager, seek_idx: &mu
     let idx_type = src.read_byte()?;
     validate!(sub_type == 0 && idx_type == 1);
     let entries = src.read_u32le()? as usize;
-    validate!(size == 24 + entries * 4 * entry_size);
+    validate!(size >= 24 + entries * 4 * entry_size);
     src.read_tag()?; //chunk id
     let base_offset = src.read_u64le()?;
     src.read_u32le()?; //reserved