realmedia/rv3040: ignore slices with wrong headers
[nihav.git] / nihav-realmedia / src / codecs / rv3040.rs
index f7f5334aa2dfe48c99e00ba08c2fe30a26e7c783..e45b62b0682204306551761a04f147b1a3871264 100644 (file)
@@ -1,51 +1,15 @@
 use nihav_core::formats::YUV420_FORMAT;
 use nihav_core::frame::{NABufferType, NAVideoInfo, NAVideoBuffer, NAVideoBufferRef, FrameType, alloc_video_buffer};
-use nihav_core::codecs::{NADecoderSupport, MV, ZERO_MV, DecoderError, DecoderResult, IPBShuffler};
+use nihav_core::codecs::{NADecoderSupport, DecoderError, DecoderResult};
+use nihav_codec_support::codecs::{MV, ZERO_MV, IPBShuffler};
 use nihav_core::io::bitreader::{BitReader,BitReaderMode};
 use nihav_core::io::intcode::*;
+use nihav_codec_support::data::GenericCache;
 use std::mem;
 
 use super::rv34codes::*;
 use super::rv34dsp::*;
 
-pub struct GenericCache<T: Copy> {
-    pub height: usize,
-    pub stride: usize,
-    pub xpos:   usize,
-    pub data:   Vec<T>,
-    pub default: T,
-}
-
-impl<T:Copy> GenericCache<T> {
-    pub fn new(height: usize, stride: usize, default: T) -> Self {
-        let mut ret = Self {
-                stride,
-                height,
-                xpos:   0,
-                data:   Vec::with_capacity((height + 1) * stride),
-                default,
-            };
-        ret.reset();
-        ret
-    }
-    fn full_size(&self) -> usize { self.stride * (self.height + 1) }
-    pub fn reset(&mut self) {
-        self.data.truncate(0);
-        let size = self.full_size();
-        self.data.resize(size, self.default);
-        self.xpos = self.stride + 1;
-    }
-    pub fn update_row(&mut self) {
-        for i in 0..self.stride {
-            self.data[i] = self.data[self.height * self.stride + i];
-        }
-        self.data.truncate(self.stride);
-        let size = self.full_size();
-        self.data.resize(size, self.default);
-        self.xpos = self.stride + 1;
-    }
-}
-
 trait RV34MVScale {
     fn scale(&self, trd: u16, trb: u16) -> (MV, MV);
 }
@@ -551,7 +515,7 @@ fn parse_slice_offsets(src: &[u8], offsets: &mut Vec<usize>) -> DecoderResult<()
 
     if ini_off >= src.len() { return Err(DecoderError::ShortData); }
 
-    let mut br = BitReader::new(&src[1..], ini_off - 1, BitReaderMode::BE);
+    let mut br = BitReader::new(&src[1..ini_off], BitReaderMode::BE);
 
     for i in 0..num_slices {
         br.skip(32)?;
@@ -575,10 +539,23 @@ fn decode_slice_header(br: &mut BitReader, bd: &mut RV34BitstreamDecoder, slice_
     if slice_no < slice_offs.len() - 1 {
         let cur_pos = br.tell() as u32;
         br.seek((slice_offs[slice_no + 1] * 8) as u32)?;
-        let nhdr = bd.decode_slice_header(br, shdr.width, shdr.height)?;
+        if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
+            validate!(nhdr.start > shdr.start);
+            shdr.end = nhdr.start;
+        } else {
+            if slice_no + 2 < slice_offs.len() {
+                br.seek((slice_offs[slice_no + 2] * 8) as u32)?;
+                if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
+                    validate!(nhdr.start > shdr.start);
+                    shdr.end = nhdr.start;
+                } else {
+                    shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
+                }
+            } else {
+                shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
+            }
+        }
         br.seek(cur_pos)?;
-        validate!(nhdr.start > shdr.start);
-        shdr.end = nhdr.start;
     } else {
         shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
     }
@@ -716,13 +693,13 @@ fn decode_mv(br: &mut BitReader) -> DecoderResult<MV> {
     Ok(MV{ x, y })
 }
 
-fn do_mc_16x16(dsp: &Box<dyn RV34DSP>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, mb_y: usize, mv: MV, avg: bool) {
+fn do_mc_16x16(dsp: &Box<dyn RV34DSP + Send>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, mb_y: usize, mv: MV, avg: bool) {
     dsp.do_luma_mc  (buf, prevbuf, mb_x * 16, mb_y * 16,    mv, true, avg);
     dsp.do_chroma_mc(buf, prevbuf, mb_x *  8, mb_y *  8, 1, mv, true, avg);
     dsp.do_chroma_mc(buf, prevbuf, mb_x *  8, mb_y *  8, 2, mv, true, avg);
 }
 
-fn do_mc_8x8(dsp: &Box<dyn RV34DSP>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, xoff: usize, mb_y: usize, yoff: usize, mv: MV, avg: bool) {
+fn do_mc_8x8(dsp: &Box<dyn RV34DSP + Send>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, xoff: usize, mb_y: usize, yoff: usize, mv: MV, avg: bool) {
     dsp.do_luma_mc  (buf, prevbuf, mb_x * 16 + xoff * 8, mb_y * 16 + yoff * 8,    mv, false, avg);
     dsp.do_chroma_mc(buf, prevbuf, mb_x *  8 + xoff * 4, mb_y *  8 + yoff * 4, 1, mv, false, avg);
     dsp.do_chroma_mc(buf, prevbuf, mb_x *  8 + xoff * 4, mb_y *  8 + yoff * 4, 2, mv, false, avg);
@@ -754,7 +731,7 @@ fn do_avg(cdsp: &RV34CommonDSP, buf: &mut NAVideoBuffer<u8>, avg_buf: &NAVideoBu
 pub struct RV34Decoder {
     is_rv30:    bool,
     coderead:   RV34Codes,
-    dsp:        Box<dyn RV34DSP>,
+    dsp:        Box<dyn RV34DSP + Send>,
     cdsp:       RV34CommonDSP,
     width:      usize,
     height:     usize,
@@ -772,7 +749,7 @@ pub struct RV34Decoder {
 }
 
 impl RV34Decoder {
-    pub fn new(is_rv30: bool, dsp: Box<dyn RV34DSP>) -> Self {
+    pub fn new(is_rv30: bool, dsp: Box<dyn RV34DSP + Send>) -> Self {
         let tmp_vinfo = NAVideoInfo::new(16, 16, false, YUV420_FORMAT);
         let vt = alloc_video_buffer(tmp_vinfo, 4).unwrap();
         let vb = vt.get_vbuf();
@@ -1117,7 +1094,7 @@ impl RV34Decoder {
         parse_slice_offsets(src, &mut slice_offs)?;
         let ini_off = slice_offs.len() * 8 + 1;
 
-        let mut br = BitReader::new(&src[ini_off..], src.len() - ini_off, BitReaderMode::BE);
+        let mut br = BitReader::new(&src[ini_off..], BitReaderMode::BE);
         let hdr0 = decode_slice_header(&mut br, bd, 0, slice_offs.as_slice(), self.width, self.height)?;
         validate!((hdr0.width != 0) && (hdr0.height != 0));
         self.width  = hdr0.width;
@@ -1143,6 +1120,22 @@ impl RV34Decoder {
                 self.base_ts += 1 << 13;
             }
         }
+        match hdr0.ftype {
+            FrameType::P => {
+                if self.ipbs.get_lastref().is_none() {
+                    return Err(DecoderError::MissingReference);
+                }
+            },
+            FrameType::B => {
+                if self.ipbs.get_lastref().is_none() {
+                    return Err(DecoderError::MissingReference);
+                }
+                if self.ipbs.get_nextref().is_none() {
+                    return Err(DecoderError::MissingReference);
+                }
+            },
+            _ => {},
+        };
         let ts_diff = (self.next_ts << 3).wrapping_sub(hdr0.pts << 3) >> 3;
         let ts = self.base_ts + (self.next_ts as u64) - (ts_diff as u64);
         sstate.trd = (self.next_ts << 3).wrapping_sub(self.last_ts << 3) >> 3;
@@ -1287,4 +1280,7 @@ impl RV34Decoder {
 
         Ok((NABufferType::Video(buf), hdr0.ftype, ts))
     }
+    pub fn flush(&mut self) {
+        self.ipbs.clear();
+    }
 }