+ pub fn get_bframe(&mut self) -> DecoderResult<NABufferType> {
+ if !self.has_b || !self.cur_frm.is_some() || !self.prev_frm.is_some() {
+ return Err(DecoderError::MissingReference);
+ }
+ self.has_b = false;
+
+ let fmt = formats::YUV420_FORMAT;
+ let vinfo = NAVideoInfo::new(self.w, self.h, false, fmt);
+ let bufret = alloc_video_buffer(vinfo, 4);
+ if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
+ let mut bufinfo = bufret.unwrap();
+ let mut b_buf = bufinfo.get_vbuf().unwrap();
+
+ if let Some(ref bck_buf) = self.prev_frm {
+ if let Some(ref fwd_buf) = self.cur_frm {
+ recon_b_frame(&mut b_buf, bck_buf, fwd_buf, self.mb_w, self.mb_h, &self.b_data);
+ }
+ }
+
+ self.b_data.truncate(0);
+ Ok(bufinfo)
+ }
+}
+
+fn recon_b_frame(b_buf: &mut NAVideoBuffer<u8>, bck_buf: &NAVideoBuffer<u8>, fwd_buf: &NAVideoBuffer<u8>,
+ mb_w: usize, mb_h: usize, b_data: &Vec<BMB>) {
+ let mut cur_mb = 0;
+ for mb_y in 0..mb_h {
+ for mb_x in 0..mb_w {
+ let num_mv = b_data[cur_mb].num_mv;
+ let is_fwd = b_data[cur_mb].fwd;
+ if num_mv == 0 {
+ copy_blocks(b_buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV);
+ if !is_fwd {
+ avg_blocks(b_buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV);
+ }
+ } else if num_mv == 1 {
+ copy_blocks(b_buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, b_data[cur_mb].mv_f[0]);
+ if !is_fwd {
+ avg_blocks(b_buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, b_data[cur_mb].mv_b[0]);
+ }
+ } else {
+ for blk_no in 0..4 {
+ let xpos = mb_x * 16 + (blk_no & 1) * 8;
+ let ypos = mb_y * 16 + (blk_no & 2) * 4;
+ copy_blocks(b_buf, bck_buf, xpos, ypos, 8, 8, b_data[cur_mb].mv_f[blk_no]);
+ if !is_fwd {
+ avg_blocks(b_buf, fwd_buf, xpos, ypos, 8, 8, b_data[cur_mb].mv_b[blk_no]);
+ }
+ }
+ }
+ if num_mv != 0 && b_data[cur_mb].cbp != 0 {
+ blockdsp::add_blocks(b_buf, mb_x, mb_y, &b_data[cur_mb].blk);
+ }
+ cur_mb += 1;