aac: clear M/S flags
[nihav.git] / nihav-duck / src / codecs / vp56.rs
index 797ff910a9c84780841de05027743fffca521b8a..5abea84f07a22fcc62567db91db0f09d2bb50a35 100644 (file)
@@ -352,6 +352,7 @@ pub struct VP56Decoder {
     mb_w:       usize,
     mb_h:       usize,
     models:     VP56Models,
+    amodels:    VP56Models,
     coeffs:     [[i16; 64]; 6],
     last_mbt:   VPMBType,
 
@@ -434,6 +435,7 @@ impl VP56Decoder {
             mb_w:       0,
             mb_h:       0,
             models:     VP56Models::new(),
+            amodels:    VP56Models::new(),
             coeffs:     [[0; 64]; 6],
             last_mbt:   VPMBType::InterNoMV,
 
@@ -459,7 +461,7 @@ impl VP56Decoder {
         self.top_ctx = [vec![0; self.mb_w * 2], vec![0; self.mb_w], vec![0; self.mb_w], vec![0; self.mb_w * 2]];
     }
     pub fn init(&mut self, supp: &mut NADecoderSupport, vinfo: NAVideoInfo) -> DecoderResult<()> {
-        supp.pool_u8.set_dec_bufs(3);
+        supp.pool_u8.set_dec_bufs(3 + if vinfo.get_format().has_alpha() { 1 } else { 0 });
         supp.pool_u8.prealloc_video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, vinfo.get_format()), 4)?;
         self.set_dimensions(vinfo.get_width(), vinfo.get_height());
         self.dc_pred.resize(self.mb_w);
@@ -484,7 +486,7 @@ impl VP56Decoder {
         let hdr = br.parse_header(&mut bc)?;
         validate!((hdr.offset as usize) < aoffset); //XXX: take alpha 3 byte offset into account?
 
-        if hdr.mb_w != 0 {
+        if hdr.mb_w != 0 && (usize::from(hdr.mb_w) != self.mb_w || usize::from(hdr.mb_h) != self.mb_h) {
             self.set_dimensions((hdr.mb_w as usize) * 16, (hdr.mb_h as usize) * 16);
         }
         let fmt = if !self.has_alpha {
@@ -518,14 +520,60 @@ impl VP56Decoder {
             }
         }
 
+        let psrc = &src[if self.has_alpha { 3 } else { 0 }..aoffset];
+        self.decode_planes(br, &mut dframe, &mut bc, &hdr, psrc, false)?;
+
+        if self.has_alpha {
+            let asrc = &src[aoffset + 3..];
+            let mut bc = BoolCoder::new(asrc)?;
+            let ahdr = br.parse_header(&mut bc)?;
+            validate!(ahdr.mb_w == hdr.mb_w && ahdr.mb_h == hdr.mb_h);
+            std::mem::swap(&mut self.models, &mut self.amodels);
+            let ret = self.decode_planes(br, &mut dframe, &mut bc, &ahdr, asrc, true);
+            std::mem::swap(&mut self.models, &mut self.amodels);
+            ret?;
+            match (hdr.is_golden, ahdr.is_golden) {
+                (true, true) => { self.shuf.add_golden_frame(buf.clone()); },
+                (true, false) => {
+                    let cur_golden = self.shuf.get_golden().unwrap();
+                    let off    = cur_golden.get_offset(3);
+                    let stride = cur_golden.get_stride(3);
+                    let mut new_golden = supp.pool_u8.get_copy(&buf).unwrap();
+                    let dst = new_golden.get_data_mut().unwrap();
+                    let src = cur_golden.get_data();
+                    dst[off..][..stride * self.mb_h * 16].copy_from_slice(&src[off..][..stride * self.mb_h * 16]);
+                    self.shuf.add_golden_frame(new_golden);
+                },
+                (false, true) => {
+                    let cur_golden = self.shuf.get_golden().unwrap();
+                    let off    = cur_golden.get_offset(3);
+                    let stride = cur_golden.get_stride(3);
+                    let mut new_golden = supp.pool_u8.get_copy(&cur_golden).unwrap();
+                    let dst = new_golden.get_data_mut().unwrap();
+                    let src = buf.get_data();
+                    dst[off..][..stride * self.mb_h * 16].copy_from_slice(&src[off..][..stride * self.mb_h * 16]);
+                    self.shuf.add_golden_frame(new_golden);
+                },
+                _ => {},
+            };
+        }
+
+        if hdr.is_golden && !self.has_alpha {
+            self.shuf.add_golden_frame(buf.clone());
+        }
+        self.shuf.add_frame(buf.clone());
+
+        Ok((NABufferType::Video(buf), if hdr.is_intra { FrameType::I } else { FrameType::P }))
+    }
+    fn decode_planes(&mut self, br: &mut dyn VP56Parser, dframe: &mut NASimpleVideoFrame<u8>, bc: &mut BoolCoder, hdr: &VP56Header, src: &[u8], alpha: bool) -> DecoderResult<()> {
         let mut cr;
         if hdr.multistream {
-            let off = (if self.has_alpha { 3 } else { 0 }) + (hdr.offset as usize);
+            let off = hdr.offset as usize;
             if !hdr.use_huffman {
                 let bc2 = BoolCoder::new(&src[off..])?;
                 cr = CoeffReader::Bool(bc2);
             } else {
-                let br = BitReader::new(&src[off..aoffset], BitReaderMode::BE);
+                let br = BitReader::new(&src[off..], BitReaderMode::BE);
                 cr = CoeffReader::Huff(br);
             }
         } else {
@@ -536,10 +584,10 @@ impl VP56Decoder {
             br.reset_models(&mut self.models);
             self.reset_mbtype_models();
         } else {
-            self.decode_mode_prob_models(&mut bc)?;
-            br.decode_mv_models(&mut bc, &mut self.models.mv_models)?;
+            self.decode_mode_prob_models(bc)?;
+            br.decode_mv_models(bc, &mut self.models.mv_models)?;
         }
-        br.decode_coeff_models(&mut bc, &mut self.models, hdr.is_intra)?;
+        br.decode_coeff_models(bc, &mut self.models, hdr.is_intra)?;
         if hdr.use_huffman {
             for i in 0..2 {
                 self.models.vp6huff.dc_token_tree[i].build_codes(&self.models.coeff_models[i].dc_value_probs);
@@ -583,25 +631,12 @@ impl VP56Decoder {
             self.fstate.last_idx = [24; 4];
             for mb_x in 0..self.mb_w {
                 self.fstate.mb_x = mb_x;
-                self.decode_mb(&mut dframe, &mut bc, &mut cr, br, &hdr, false)?;
+                self.decode_mb(dframe, bc, &mut cr, br, hdr, alpha)?;
                 self.dc_pred.next_mb();
             }
             self.dc_pred.update_row();
         }
-
-        if self.has_alpha {
-            let asrc = &src[aoffset + 3..];
-            let mut bc = BoolCoder::new(asrc)?;
-            let ahdr = br.parse_header(&mut bc)?;
-            validate!(ahdr.mb_w == hdr.mb_w && ahdr.mb_h == hdr.mb_h);
-        }
-
-        if hdr.is_golden {
-            self.shuf.add_golden_frame(buf.clone());
-        }
-        self.shuf.add_frame(buf.clone());
-
-        Ok((NABufferType::Video(buf), if hdr.is_intra { FrameType::I } else { FrameType::P }))
+        Ok(())
     }
     fn reset_mbtype_models(&mut self) {
         const DEFAULT_XMITTED_PROBS: [[u8; 20]; 3] = [
@@ -662,16 +697,16 @@ impl VP56Decoder {
                 let sum = u32::from(prob_xmitted[mode * 2]) + u32::from(prob_xmitted[mode * 2 + 1]);
                 mdl.probs[9] = 255 - rescale_mb_mode_prob(u32::from(prob_xmitted[mode * 2 + 1]), sum);
 
-                let inter_mv0_weight = (cnt[0] as u32) + (cnt[2] as u32);
-                let inter_mv1_weight = (cnt[3] as u32) + (cnt[4] as u32);
-                let gold_mv0_weight = (cnt[5] as u32) + (cnt[6] as u32);
-                let gold_mv1_weight = (cnt[8] as u32) + (cnt[9] as u32);
-                let mix_weight = (cnt[1] as u32) + (cnt[7] as u32);
+                let inter_mv0_weight = cnt[0] + cnt[2];
+                let inter_mv1_weight = cnt[3] + cnt[4];
+                let gold_mv0_weight = cnt[5] + cnt[6];
+                let gold_mv1_weight = cnt[8] + cnt[9];
+                let mix_weight = cnt[1] + cnt[7];
                 mdl.probs[0] = 1 + rescale_mb_mode_prob(inter_mv0_weight + inter_mv1_weight, total);
                 mdl.probs[1] = 1 + rescale_mb_mode_prob(inter_mv0_weight, inter_mv0_weight + inter_mv1_weight);
                 mdl.probs[2] = 1 + rescale_mb_mode_prob(mix_weight, mix_weight + gold_mv0_weight + gold_mv1_weight);
-                mdl.probs[3] = 1 + rescale_mb_mode_prob(cnt[0] as u32, inter_mv0_weight);
-                mdl.probs[4] = 1 + rescale_mb_mode_prob(cnt[3] as u32, inter_mv1_weight);
+                mdl.probs[3] = 1 + rescale_mb_mode_prob(cnt[0], inter_mv0_weight);
+                mdl.probs[4] = 1 + rescale_mb_mode_prob(cnt[3], inter_mv1_weight);
                 mdl.probs[5] = 1 + rescale_mb_mode_prob(cnt[1], mix_weight);
                 mdl.probs[6] = 1 + rescale_mb_mode_prob(gold_mv0_weight, gold_mv0_weight + gold_mv1_weight);
                 mdl.probs[7] = 1 + rescale_mb_mode_prob(cnt[5], gold_mv0_weight);
@@ -891,25 +926,24 @@ impl VP56Decoder {
                 }
             }
         }
-        if !alpha {
-            for blk_no in 4..6 {
-                self.fstate.plane = blk_no - 3;
-                self.fstate.ctx_idx = blk_no - 2;
-                self.fstate.top_ctx = self.top_ctx[self.fstate.plane][mb_x];
-                match cr {
-                    CoeffReader::None              => {
-                        br.decode_block(bc, &mut self.coeffs[blk_no], &self.models.coeff_models[1], &self.models.vp6models, &mut self.fstate)?;
-                    },
-                    CoeffReader::Bool(ref mut bcc) => {
-                        br.decode_block(bcc, &mut self.coeffs[blk_no], &self.models.coeff_models[1], &self.models.vp6models, &mut self.fstate)?;
-                    },
-                    CoeffReader::Huff(ref mut brc) => {
-                        br.decode_block_huff(brc, &mut self.coeffs[blk_no], &self.models.vp6models, &self.models.vp6huff, &mut self.fstate)?;
-                    },
-                };
-                self.top_ctx[self.fstate.plane][mb_x] = self.fstate.top_ctx;
-                self.predict_dc(mb_type, mb_pos, blk_no, alpha);
-
+        for blk_no in 4..6 {
+            self.fstate.plane = blk_no - 3;
+            self.fstate.ctx_idx = blk_no - 2;
+            self.fstate.top_ctx = self.top_ctx[self.fstate.plane][mb_x];
+            match cr {
+                CoeffReader::None              => {
+                    br.decode_block(bc, &mut self.coeffs[blk_no], &self.models.coeff_models[1], &self.models.vp6models, &mut self.fstate)?;
+                },
+                CoeffReader::Bool(ref mut bcc) => {
+                    br.decode_block(bcc, &mut self.coeffs[blk_no], &self.models.coeff_models[1], &self.models.vp6models, &mut self.fstate)?;
+                },
+                CoeffReader::Huff(ref mut brc) => {
+                    br.decode_block_huff(brc, &mut self.coeffs[blk_no], &self.models.vp6models, &self.models.vp6huff, &mut self.fstate)?;
+                },
+            };
+            self.top_ctx[self.fstate.plane][mb_x] = self.fstate.top_ctx;
+            self.predict_dc(mb_type, mb_pos, blk_no, alpha);
+            if !alpha {
                 let has_ac = self.fstate.last_idx[self.fstate.ctx_idx] > 0;
                 if mb_type.is_intra() {
                     if has_ac {