replace vec.truncate(0) with vec.clear()
[nihav.git] / nihav-codec-support / src / codecs / h263 / decoder.rs
index 71c574ca0f3e807aadcc9a81a6dc43a65f4e0e26..bba8c04ce752799a458424e8ae9c050e81115dc1 100644 (file)
@@ -119,11 +119,13 @@ struct PredCoeffs {
 }
 
 const ZERO_PRED_COEFFS: PredCoeffs = PredCoeffs { hor: [[1024, 0, 0, 0, 0, 0, 0, 0]; 6], ver: [[1024, 0, 0, 0, 0, 0, 0, 0]; 6] };
+const ZERO_PRED_COEFFS2: PredCoeffs = PredCoeffs { hor: [[0x7FFF, 0, 0, 0, 0, 0, 0, 0]; 6], ver: [[0x7FFF, 0, 0, 0, 0, 0, 0, 0]; 6] };
 
 pub const H263DEC_OPT_USES_GOB: u32     = 0x0001;
 pub const H263DEC_OPT_SLICE_RESET: u32  = 0x0002;
 pub const H263DEC_OPT_HAS_B_FRAMES: u32 = 0x0004;
 pub const H263DEC_OPT_HAS_OBMC: u32     = 0x0008;
+pub const H263DEC_OPT_PRED_QUANT: u32   = 0x0010;
 
 pub struct H263BaseDecoder {
     w:          usize,
@@ -147,6 +149,7 @@ pub struct H263BaseDecoder {
     blk:        [[i16; 64]; 6],
     obmc_buf:   NAVideoBufferRef<u8>,
     obmc_blk:   Vec<(Type, BMB)>,
+    pred_quant: bool,
 }
 
 #[inline]
@@ -170,6 +173,7 @@ impl H263BaseDecoder {
         let slice_reset         = (options & H263DEC_OPT_SLICE_RESET) != 0;
         let may_have_b_frames   = (options & H263DEC_OPT_HAS_B_FRAMES) != 0;
         let has_obmc            = (options & H263DEC_OPT_HAS_OBMC) != 0;
+        let pred_quant          = (options & H263DEC_OPT_PRED_QUANT) != 0;
 
         let vbuf = alloc_video_buffer(NAVideoInfo::new(64, 64, false, YUV420_FORMAT), 4).unwrap();
         let obmc_buf = vbuf.get_vbuf().unwrap();
@@ -183,6 +187,7 @@ impl H263BaseDecoder {
             pred_coeffs: Vec::new(),
             is_gob, slice_reset,
             may_have_b_frames, has_obmc,
+            pred_quant,
             mv_data: Vec::new(),
             blk: [[0; 64]; 6],
             obmc_buf,
@@ -209,7 +214,7 @@ impl H263BaseDecoder {
     }
     pub fn get_dimensions(&self) -> (usize, usize) { (self.w, self.h) }
 
-    fn decode_intra_mb(&mut self, bd: &mut BlockDecoder, bdsp: &BlockDSP, mb_pos: usize, binfo: &BlockInfo, sstate: &SliceState, apply_acpred: bool) -> DecoderResult<()> {
+    fn decode_intra_mb(&mut self, bd: &mut dyn BlockDecoder, bdsp: &dyn BlockDSP, mb_pos: usize, binfo: &BlockInfo, sstate: &SliceState, apply_acpred: bool) -> DecoderResult<()> {
         for i in 0..6 {
             bd.decode_block_intra(&binfo, &sstate, binfo.get_q(), i, (binfo.cbp & (1 << (5 - i))) != 0, &mut self.blk[i])?;
             if apply_acpred && (binfo.acpred != ACPredMode::None) {
@@ -282,7 +287,112 @@ impl H263BaseDecoder {
         }
         Ok(())
     }
-    fn decode_inter_mb(&mut self, bd: &mut BlockDecoder, bdsp: &BlockDSP, binfo: &BlockInfo, sstate: &SliceState) -> DecoderResult<()> {
+    #[allow(clippy::comparison_chain)]
+    fn decode_intra_mb_pred_quant(&mut self, bd: &mut dyn BlockDecoder, bdsp: &dyn BlockDSP, mb_pos: usize, binfo: &BlockInfo, sstate: &SliceState, apply_acpred: bool) -> DecoderResult<()> {
+        for i in 0..6 {
+            bd.decode_block_intra(&binfo, &sstate, binfo.get_q(), i, (binfo.cbp & (1 << (5 - i))) != 0, &mut self.blk[i])?;
+            let q = if binfo.get_q() < 8 {
+                    8
+                } else {
+                    i16::from(binfo.get_q() * 2)
+                };
+            let qadd = (q + 1) >> 1;
+            let quant_gray = 1024 / q;
+            if apply_acpred && (binfo.acpred != ACPredMode::None) {
+                let has_b = (i == 1) || (i == 3) || !sstate.first_mb;
+                let has_a = (i == 2) || (i == 3) || !sstate.first_line;
+                let (b_mb, b_blk) = if has_b {
+                        if (i == 1) || (i == 3) {
+                            (mb_pos, i - 1)
+                        } else if i < 4 {
+                            (mb_pos - 1, i + 1)
+                        } else {
+                            (mb_pos - 1, i)
+                        }
+                    } else { (0, 0) };
+                let (a_mb, a_blk) = if has_a {
+                        if (i == 2) || (i == 3) {
+                            (mb_pos, i - 2)
+                        } else if i < 4 {
+                            (mb_pos - self.mb_w, i + 2)
+                        } else {
+                            (mb_pos - self.mb_w, i)
+                        }
+                    } else { (0, 0) };
+                let dc_a = if has_a && self.pred_coeffs[a_mb].ver[a_blk][0] != 0x7FFF {
+                        self.pred_coeffs[a_mb].ver[a_blk][0]
+                    } else {
+                        quant_gray
+                    };
+                let dc_b = if has_b && self.pred_coeffs[b_mb].hor[b_blk][0] != 0x7FFF {
+                        self.pred_coeffs[b_mb].hor[b_blk][0]
+                    } else {
+                        quant_gray
+                    };
+                let dc = match binfo.acpred {
+                    ACPredMode::DC   => {
+                                if has_a && has_b {
+                                    (dc_a + dc_b + 1) >> 1
+                                } else if has_a {
+                                    dc_a
+                                } else if has_b {
+                                    dc_b
+                                } else {
+                                    quant_gray
+                                }
+                            },
+                    ACPredMode::Hor  => {
+                            if has_b {
+                                for k in 1..8 {
+                                    self.blk[i][k * 8] += self.pred_coeffs[b_mb].hor[b_blk][k];
+                                }
+                                for k in 1..8 {
+                                    self.blk[i][k * 8] = clip_ac(self.blk[i][k * 8]);
+                                }
+                                dc_b
+                            } else {
+                                quant_gray
+                            }
+                        },
+                    ACPredMode::Ver  => {
+                            if has_a {
+                                for k in 1..8 {
+                                    self.blk[i][k] += self.pred_coeffs[a_mb].ver[a_blk][k];
+                                }
+                                for k in 1..8 {
+                                    self.blk[i][k] = clip_ac(self.blk[i][k]);
+                                }
+                                dc_a
+                            } else {
+                                quant_gray
+                            }
+                        },
+                    ACPredMode::None => { 0 },
+                };
+                self.blk[i][0] += dc;
+                for t in 0..8 { self.pred_coeffs[mb_pos].hor[i][t] = self.blk[i][t * 8]; }
+                for t in 0..8 { self.pred_coeffs[mb_pos].ver[i][t] = self.blk[i][t]; }
+            }
+            if apply_acpred {
+                let start = if binfo.get_q() < 8 {
+                        self.blk[i][0] <<= 3;
+                        1
+                    } else {
+                        0
+                    };
+                for el in self.blk[i].iter_mut().skip(start) {
+                    if *el > 0 {
+                        *el = *el * q + qadd;
+                    } else if *el < 0 {
+                        *el = *el * q - qadd;
+                    }
+                }
+            }
+            bdsp.idct(&mut self.blk[i]);
+        }
+        Ok(())
+    }
+    fn decode_inter_mb(&mut self, bd: &mut dyn BlockDecoder, bdsp: &dyn BlockDSP, binfo: &BlockInfo, sstate: &SliceState) -> DecoderResult<()> {
         for i in 0..6 {
             bd.decode_block_inter(&binfo, &sstate, binfo.get_q(), i, ((binfo.cbp >> (5 - i)) & 1) != 0, &mut self.blk[i])?;
             bdsp.idct(&mut self.blk[i]);
@@ -301,6 +411,7 @@ impl H263BaseDecoder {
             bi.mv_f[blk_no]
         }
     }
+    #[allow(clippy::cognitive_complexity)]
     fn reconstruct_obmc(&mut self, buf: &mut NAVideoBuffer<u8>, slice_start: usize, start: usize, end: usize, slice_end: bool) -> usize {
         let mut mb_x = start % self.mb_w;
         let mut mb_y = start / self.mb_w;
@@ -404,7 +515,8 @@ impl H263BaseDecoder {
         }
         mb_pos
     }
-    pub fn parse_frame(&mut self, bd: &mut BlockDecoder, bdsp: &BlockDSP) -> DecoderResult<NABufferType> {
+    #[allow(clippy::cognitive_complexity)]
+    pub fn parse_frame(&mut self, bd: &mut dyn BlockDecoder, bdsp: &dyn BlockDSP) -> DecoderResult<NABufferType> {
         let pinfo = bd.decode_pichdr()?;
         let mut mvi = MVInfo::new();
         let mut mvi2 = MVInfo::new();
@@ -426,16 +538,16 @@ impl H263BaseDecoder {
             if capacity < self.num_mb {
                 self.obmc_blk.reserve(self.num_mb - capacity);
             }
-            self.obmc_blk.truncate(0);
+            self.obmc_blk.clear();
         }
 
         if self.has_b {
-            self.mv_data.truncate(0);
+            self.mv_data.clear();
         }
 
         let save_b_data = pinfo.mode.is_ref() && self.may_have_b_frames;
         if save_b_data {
-            self.mv_data.truncate(0);
+            self.mv_data.clear();
         }
         let is_b = pinfo.mode == Type::B;
 
@@ -468,8 +580,12 @@ impl H263BaseDecoder {
         let mut mb_pos = 0;
         let apply_acpred = /*(pinfo.mode == Type::I) && */pinfo.plusinfo.is_some() && pinfo.plusinfo.unwrap().aic;
         if apply_acpred {
-            self.pred_coeffs.truncate(0);
-            self.pred_coeffs.resize(self.mb_w * self.mb_h, ZERO_PRED_COEFFS);
+            self.pred_coeffs.clear();
+            if !self.pred_quant {
+                self.pred_coeffs.resize(self.mb_w * self.mb_h, ZERO_PRED_COEFFS);
+            } else {
+                self.pred_coeffs.resize(self.mb_w * self.mb_h, ZERO_PRED_COEFFS2);
+            }
         }
         sstate.quant = slice.quant;
         let mut obmc_start = 0;
@@ -505,7 +621,11 @@ impl H263BaseDecoder {
                     if save_b_data {
                         self.mv_data.push(BlockMVInfo::Intra);
                     }
-                    self.decode_intra_mb(bd, bdsp, mb_pos, &binfo, &sstate, apply_acpred)?;
+                    if !self.pred_quant {
+                        self.decode_intra_mb(bd, bdsp, mb_pos, &binfo, &sstate, apply_acpred)?;
+                    } else {
+                        self.decode_intra_mb_pred_quant(bd, bdsp, mb_pos, &binfo, &sstate, apply_acpred)?;
+                    }
                     blockdsp::put_blocks(&mut buf, mb_x, mb_y, &self.blk);
                     mvi.set_zero_mv(mb_x);
                     if is_b {
@@ -661,7 +781,7 @@ impl H263BaseDecoder {
         self.ipbs.clear();
     }
 
-    pub fn get_bframe(&mut self, bdsp: &BlockDSP) -> DecoderResult<NABufferType> {
+    pub fn get_bframe(&mut self, bdsp: &dyn BlockDSP) -> DecoderResult<NABufferType> {
         if !self.has_b || self.ipbs.get_lastref().is_none() || self.ipbs.get_nextref().is_none() {
             return Err(DecoderError::MissingReference);
         }
@@ -676,12 +796,12 @@ impl H263BaseDecoder {
             recon_b_frame(b_buf, bck_buf.clone(), fwd_buf.clone(), self.mb_w, self.mb_h, self.b_data.as_slice(), bdsp);
         }
 
-        self.b_data.truncate(0);
+        self.b_data.clear();
         Ok(bufinfo)
     }
 }
 
-fn recon_b_mb(buf: &mut NAVideoBuffer<u8>, ipbs: &mut IPBShuffler, bdsp: &BlockDSP, mvi: &mut MVInfo, mvi2: &mut MVInfo, mb_pos: usize, mb_w: usize, sstate: &SliceState, binfo: &BlockInfo, mv_data: &[BlockMVInfo], bsdiff: u16, tsdiff: u16) {
+fn recon_b_mb(buf: &mut NAVideoBuffer<u8>, ipbs: &mut IPBShuffler, bdsp: &dyn BlockDSP, mvi: &mut MVInfo, mvi2: &mut MVInfo, mb_pos: usize, mb_w: usize, sstate: &SliceState, binfo: &BlockInfo, mv_data: &[BlockMVInfo], bsdiff: u16, tsdiff: u16) {
     let mb_x = mb_pos % mb_w;
     let mb_y = mb_pos / mb_w;
 
@@ -745,7 +865,7 @@ fn recon_b_mb(buf: &mut NAVideoBuffer<u8>, ipbs: &mut IPBShuffler, bdsp: &BlockD
 }
 
 fn recon_b_frame(mut b_buf: NAVideoBufferRef<u8>, bck_buf: NAVideoBufferRef<u8>, fwd_buf: NAVideoBufferRef<u8>,
-                 mb_w: usize, mb_h: usize, b_data: &[BMB], bdsp: &BlockDSP) {
+                 mb_w: usize, mb_h: usize, b_data: &[BMB], bdsp: &dyn BlockDSP) {
     let mut cbpi = CBPInfo::new();
     let mut cur_mb = 0;
     cbpi.reset(mb_w);