i263: decode B-frames somehow
authorKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 9 Jun 2017 12:24:01 +0000 (14:24 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 9 Jun 2017 15:58:21 +0000 (17:58 +0200)
src/codecs/blockdec.rs
src/codecs/h263code.rs
src/codecs/intel263.rs

index 0326f84984f984ea06368876a5c71bec6b6449e3..23e22d41e628d45193c1e10a5c6e10aad62a45ca 100644 (file)
@@ -1,5 +1,5 @@
 use std::mem;
-use std::ops::Add;
+use std::ops::{Add, Sub};
 use super::*;
 use super::blockdsp;
 use super::h263code::*;
@@ -10,6 +10,21 @@ pub enum Type {
     I, P, Skip, Special
 }
 
+#[allow(dead_code)]
+#[derive(Debug,Clone,Copy)]
+pub struct PBInfo {
+    trb:        u8,
+    dbquant:    u8,
+}
+
+impl PBInfo {
+    pub fn new(trb: u8, dbquant: u8) -> Self {
+        PBInfo{ trb: trb, dbquant: dbquant }
+    }
+    pub fn get_trb(&self) -> u8 { self.trb }
+    pub fn get_dbquant(&self) -> u8 { self.dbquant }
+}
+
 #[allow(dead_code)]
 #[derive(Debug,Clone,Copy)]
 pub struct PicInfo {
@@ -19,14 +34,14 @@ pub struct PicInfo {
     quant:  u8,
     apm:    bool,
     umv:    bool,
-    pb:     bool,
+    pb:     Option<PBInfo>,
     ts:     u8,
 }
 
 #[allow(dead_code)]
 impl PicInfo {
-    pub fn new(w: usize, h: usize, mode: Type, quant: u8, apm: bool, umv: bool, pb: bool, ts: u8) -> Self {
-        PicInfo{ w: w, h: h, mode: mode, quant: quant, apm: apm, umv: umv, pb: pb, ts: ts }
+    pub fn new(w: usize, h: usize, mode: Type, quant: u8, apm: bool, umv: bool, ts: u8, pb: Option<PBInfo>) -> Self {
+        PicInfo{ w: w, h: h, mode: mode, quant: quant, apm: apm, umv: umv, ts: ts, pb: pb }
     }
     pub fn get_width(&self) -> usize { self.w }
     pub fn get_height(&self) -> usize { self.h }
@@ -34,8 +49,9 @@ impl PicInfo {
     pub fn get_quant(&self) -> u8 { self.quant }
     pub fn get_apm(&self) -> bool { self.apm }
     pub fn get_umv(&self) -> bool { self.umv }
-    pub fn is_pb(&self) -> bool { self.pb }
+    pub fn is_pb(&self) -> bool { self.pb.is_some() }
     pub fn get_ts(&self) -> u8 { self.ts }
+    pub fn get_pbinfo(&self) -> PBInfo { self.pb.unwrap() }
 }
 
 #[derive(Debug,Clone,Copy)]
@@ -109,6 +125,19 @@ impl MV {
         }
         new_mv
     }
+    fn scale(&self, trb: u8, trd: u8) -> Self {
+        if (trd == 0) || (trb == 0) {
+            ZERO_MV
+        } else {
+            MV { x: (self.x * (trb as i16)) / (trd as i16), y: (self.y * (trb as i16)) / (trd as i16) }
+        }
+    }
+    fn b_sub(pvec: MV, fwdvec: MV, bvec: MV, trb: u8, trd: u8) -> Self {
+        let bscale = (trb as i16) - (trd as i16);
+        let x = if bvec.x != 0 { fwdvec.x - pvec.x } else if trd != 0 { bscale * pvec.x / (trd as i16) } else { 0 };
+        let y = if bvec.y != 0 { fwdvec.y - pvec.y } else if trd != 0 { bscale * pvec.y / (trd as i16) } else { 0 };
+        MV { x: x, y: y }
+    }
 }
 
 pub const ZERO_MV: MV = MV { x: 0, y: 0 };
@@ -118,6 +147,11 @@ impl Add for MV {
     fn add(self, other: MV) -> MV { MV { x: self.x + other.x, y: self.y + other.y } }
 }
 
+impl Sub for MV {
+    type Output = MV;
+    fn sub(self, other: MV) -> MV { MV { x: self.x - other.x, y: self.y - other.y } }
+}
+
 #[derive(Debug,Clone,Copy)]
 pub struct BlockInfo {
     intra:   bool,
@@ -129,8 +163,18 @@ pub struct BlockInfo {
     num_mv:  usize,
     bpart:   bool,
     b_cbp:   u8,
-    mv2:     [MV; 4],
+    mv2:     [MV; 2],
     num_mv2: usize,
+    fwd:     bool,
+}
+
+#[allow(dead_code)]
+#[derive(Debug,Clone,Copy)]
+pub struct BBlockInfo {
+    present: bool,
+    cbp:     u8,
+    num_mv:  usize,
+    fwd:     bool,
 }
 
 #[allow(dead_code)]
@@ -146,8 +190,9 @@ impl BlockInfo {
             num_mv:  0,
             bpart:   false,
             b_cbp:   0,
-            mv2:     [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)],
+            mv2:     [ZERO_MV, ZERO_MV],
             num_mv2: 0,
+            fwd:     false,
         }
     }
     pub fn is_intra(&self) -> bool { self.intra }
@@ -163,28 +208,44 @@ impl BlockInfo {
     pub fn get_mv2(&self, idx: usize) -> MV { self.mv2[idx] }
     pub fn set_mv(&mut self, mvs: &[MV]) {
         if mvs.len() > 0 { self.skip = false; }
-        self.bpart = true;
         let mut mv_arr: [MV; 4] = [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)];
         for i in 0..mvs.len() { mv_arr[i] = mvs[i]; }
         self.mv     = mv_arr;
         self.num_mv = mvs.len();
     }
-    pub fn set_mv2(&mut self, cbp: u8, mvs: &[MV]) {
-        self.bpart = true;
-        self.b_cbp = cbp;
-        let mut mv_arr: [MV; 4] = [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)];
+    pub fn set_bpart(&mut self, bbinfo: BBlockInfo) {
+        self.bpart = bbinfo.present;
+        self.b_cbp = bbinfo.cbp;
+        self.fwd   = bbinfo.fwd;
+        self.num_mv2 = bbinfo.get_num_mv();
+    }
+    pub fn set_b_mv(&mut self, mvs: &[MV]) {
+        if mvs.len() > 0 { self.skip = false; }
+        let mut mv_arr: [MV; 2] = [ZERO_MV, ZERO_MV];
         for i in 0..mvs.len() { mv_arr[i] = mvs[i]; }
-        self.mv2     = mv_arr;
-        self.num_mv2 = mvs.len();
+        self.mv2    = mv_arr;
+    }
+    pub fn is_b_fwd(&self) -> bool { self.fwd }
+}
+
+impl BBlockInfo {
+    pub fn new(present: bool, cbp: u8, num_mv: usize, fwd: bool) -> Self {
+        BBlockInfo {
+            present: present,
+            cbp:     cbp,
+            num_mv:  num_mv,
+            fwd:     fwd,
+        }
     }
+    pub fn get_num_mv(&self) -> usize { self.num_mv }
 }
 
 pub trait BlockDecoder {
     fn decode_pichdr(&mut self) -> DecoderResult<PicInfo>;
     fn decode_slice_header(&mut self, pinfo: &PicInfo) -> DecoderResult<Slice>;
     fn decode_block_header(&mut self, pinfo: &PicInfo, sinfo: &Slice) -> DecoderResult<BlockInfo>;
-    fn decode_block_intra(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>;
-    fn decode_block_inter(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>;
+    fn decode_block_intra(&mut self, info: &BlockInfo, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>;
+    fn decode_block_inter(&mut self, info: &BlockInfo, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>;
     fn calc_mv(&mut self, vec: MV);
     fn is_slice_end(&mut self) -> bool;
 }
@@ -286,6 +347,29 @@ fn copy_blocks(dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, xpos: usize
     blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_FUNCS);
 }
 
+fn avg_blocks(dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) {
+    let srcx = ((mv.x >> 1) as isize) + (xpos as isize);
+    let srcy = ((mv.y >> 1) as isize) + (ypos as isize);
+    let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
+
+    blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_AVG_FUNCS);
+}
+
+#[allow(dead_code)]
+#[derive(Clone,Copy)]
+struct BMB {
+    num_mv: usize,
+    mv_f:   [MV; 4],
+    mv_b:   [MV; 4],
+    fwd:    bool,
+    blk:    [[i16; 64]; 6],
+    cbp:    u8,
+}
+
+impl BMB {
+    fn new() -> Self { BMB {blk: [[0; 64]; 6], cbp: 0, fwd: false, mv_f: [ZERO_MV; 4], mv_b: [ZERO_MV; 4], num_mv: 0} }
+}
+
 pub struct DCT8x8VideoDecoder {
     w:          usize,
     h:          usize,
@@ -295,6 +379,9 @@ pub struct DCT8x8VideoDecoder {
     ftype:      Type,
     prev_frm:   Option<NAVideoBuffer<u8>>,
     cur_frm:    Option<NAVideoBuffer<u8>>,
+    last_ts:    u8,
+    has_b:      bool,
+    b_data:     Vec<BMB>,
 }
 
 #[allow(dead_code)]
@@ -304,6 +391,8 @@ impl DCT8x8VideoDecoder {
             w: 0, h: 0, mb_w: 0, mb_h: 0, num_mb: 0,
             ftype: Type::Special,
             prev_frm: None, cur_frm: None,
+            last_ts: 0,
+            has_b: false, b_data: Vec::new(),
         }
     }
 
@@ -312,7 +401,7 @@ impl DCT8x8VideoDecoder {
 
     pub fn parse_frame(&mut self, bd: &mut BlockDecoder) -> DecoderResult<NABufferType> {
         let pinfo = bd.decode_pichdr()?;
-        let mut mvi  = MVInfo::new();
+        let mut mvi = MVInfo::new();
 
 //todo handle res change
         self.w = pinfo.w;
@@ -321,10 +410,18 @@ impl DCT8x8VideoDecoder {
         self.mb_h = (pinfo.h + 15) >> 4;
         self.num_mb = self.mb_w * self.mb_h;
         self.ftype = pinfo.mode;
+        self.has_b = pinfo.is_pb();
+
+        if self.has_b {
+            self.b_data.truncate(0);
+        }
 
         mem::swap(&mut self.cur_frm, &mut self.prev_frm);
 //        if self.ftype == Type::I && !pinfo.is_pb() { self.prev_frm = None; }
 
+        let tsdiff = pinfo.ts.wrapping_sub(self.last_ts);
+        let bsdiff = if pinfo.is_pb() { pinfo.get_pbinfo().get_trb() } else { 0 };
+
         let fmt = formats::YUV420_FORMAT;
         let vinfo = NAVideoInfo::new(self.w, self.h, false, fmt);
         let bufret = alloc_video_buffer(vinfo, 4);
@@ -332,17 +429,6 @@ impl DCT8x8VideoDecoder {
         let mut bufinfo = bufret.unwrap();
         let mut buf = bufinfo.get_vbuf().unwrap();
 
-        let mut bbuf;
-
-        if self.prev_frm.is_some() && pinfo.is_pb() {
-            let bufret = alloc_video_buffer(vinfo, 4);
-            if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
-            let mut bbufinfo = bufret.unwrap();
-            bbuf = Some(bbufinfo.get_vbuf().unwrap());
-        } else {
-            bbuf = None;
-        }
-
         let mut slice = Slice::get_default_slice(&pinfo);
         mvi.reset(self.mb_w, 0, pinfo.get_umv());
 
@@ -362,7 +448,7 @@ impl DCT8x8VideoDecoder {
 //println!("mb {}.{} CBP {:X} type {:?}, {} mvs skip {}", mb_x,mb_y, cbp, binfo.get_mode(), binfo.get_num_mvs(),binfo.is_skipped());
                 if binfo.is_intra() {
                     for i in 0..6 {
-                        bd.decode_block_intra(&binfo, i, (cbp & (1 << (5 - i))) != 0, &mut blk[i])?;
+                        bd.decode_block_intra(&binfo, binfo.get_q(), i, (cbp & (1 << (5 - i))) != 0, &mut blk[i])?;
                         h263_idct(&mut blk[i]);
                     }
                     blockdsp::put_blocks(&mut buf, mb_x, mb_y, &blk);
@@ -387,7 +473,7 @@ impl DCT8x8VideoDecoder {
 //println!("");
                     }
                     for i in 0..6 {
-                        bd.decode_block_inter(&binfo, i, ((cbp >> (5 - i)) & 1) != 0, &mut blk[i])?;
+                        bd.decode_block_inter(&binfo, binfo.get_q(), i, ((cbp >> (5 - i)) & 1) != 0, &mut blk[i])?;
                         h263_idct(&mut blk[i]);
                     }
                     blockdsp::add_blocks(&mut buf, mb_x, mb_y, &blk);
@@ -397,44 +483,109 @@ impl DCT8x8VideoDecoder {
                         copy_blocks(&mut buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV);
                     }
                 }
-                if pinfo.is_pb() && binfo.has_b_part() {
-                    let mut blk: [[i16; 64]; 6] = [[0; 64]; 6];
+                if pinfo.is_pb() {
+                    let mut b_mb = BMB::new();
                     let cbp = binfo.get_cbp_b();
+                    let bq = (((pinfo.get_pbinfo().get_dbquant() + 5) as u16) * (binfo.get_q() as u16)) >> 2;
+                    let bquant;
+                    if bq < 1 { bquant = 1; }
+                    else if bq > 31 { bquant = 31; }
+                    else { bquant = bq as u8; }
+
+                    b_mb.cbp = cbp;
                     for i in 0..6 {
-                        bd.decode_block_inter(&binfo, i, (cbp & (1 << (5 - i))) != 0, &mut blk[i])?;
-                        h263_idct(&mut blk[i]);
+                        bd.decode_block_inter(&binfo, bquant, i, (cbp & (1 << (5 - i))) != 0, &mut b_mb.blk[i])?;
+                        h263_idct(&mut b_mb.blk[i]);
                     }
-                    if let Some(ref mut b_buf) = bbuf {
-/*                        let is_fwd = false;
-                        if binfo.get_num_mvs() == 1 { //todo scale
-                            let mv_f = MV::add_umv(binfo.get_mv(0), binfo.get_mv2(0), pinfo.get_umv());
-                            let mv_b = ZERO_MV//if component = 0 then scaled else mv_f - component
-                        } else {
-                        }*/
-                        if let Some(ref srcbuf) = self.prev_frm {
-                            copy_blocks(b_buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV);
-                            blockdsp::add_blocks(b_buf, mb_x, mb_y, &blk);
+
+                    let is_fwd = binfo.is_b_fwd();
+                    b_mb.fwd = is_fwd;
+                    b_mb.num_mv = binfo.get_num_mvs();
+                    if binfo.get_num_mvs() == 0 {
+                        b_mb.num_mv = 1;
+                        b_mb.mv_f[0] = binfo.get_mv2(1);
+                        b_mb.mv_b[0] = binfo.get_mv2(0);
+                    } if binfo.get_num_mvs() == 1 {
+                        let src_mv = if is_fwd { ZERO_MV } else { binfo.get_mv(0).scale(bsdiff, tsdiff) };
+                        let mv_f = MV::add_umv(src_mv, binfo.get_mv2(0), pinfo.get_umv());
+                        let mv_b = MV::b_sub(binfo.get_mv(0), mv_f, binfo.get_mv2(0), bsdiff, tsdiff);
+                        b_mb.mv_f[0] = mv_f;
+                        b_mb.mv_b[0] = mv_b;
+                    } else {
+                        for blk_no in 0..4 {
+                            let src_mv = if is_fwd { ZERO_MV } else { binfo.get_mv(blk_no).scale(bsdiff, tsdiff) };
+                            let mv_f = MV::add_umv(src_mv, binfo.get_mv2(0), pinfo.get_umv());
+                            let mv_b = MV::b_sub(binfo.get_mv(blk_no), mv_f, binfo.get_mv2(0), bsdiff, tsdiff);
+                            b_mb.mv_f[blk_no] = mv_f;
+                            b_mb.mv_b[blk_no] = mv_b;
                         }
                     }
+                    self.b_data.push(b_mb);
                 }
-
             }
             mvi.update_row();
         }
         self.cur_frm = Some(buf);
-        if pinfo.is_pb() {
-            return Ok(NABufferType::Video(bbuf.unwrap()));
-        } 
-println!("unpacked all");
+        self.last_ts = pinfo.ts;
+//println!("unpacked all");
         Ok(bufinfo)
     }
 
-    pub fn get_stored_pframe(&mut self) -> DecoderResult<NABufferType> {
-        if let Some(_) = self.cur_frm {
-            let buf = self.cur_frm.clone().unwrap();
-            Ok(NABufferType::Video(buf))
-        } else {
-            Err(DecoderError::MissingReference)
+    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;
         }
     }
 }
index d38af9585975195f191feb453ab36f212f1a5434..594a63c47da1ead3aa13f7c7e60b73ff51c6ce7b 100644 (file)
@@ -267,3 +267,69 @@ fn h263_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw:
 
 pub const H263_INTERP_FUNCS: &[fn(&mut [u8], usize, &[u8], usize, usize, usize)] = &[
         h263_interp00, h263_interp01, h263_interp10, h263_interp11 ];
+
+fn h263_interp00_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw {
+            let a = dst[didx + x] as u16;
+            let b = src[sidx + x] as u16;
+            dst[didx + x] = ((a + b + 1) >> 1) as u8;
+        }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn h263_interp01_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw {
+            let a = dst[didx + x] as u16;
+            let b = ((src[sidx + x] as u16) + (src[sidx + x + 1] as u16) + 1) >> 1;
+            dst[didx + x] = ((a + b + 1) >> 1) as u8;
+        }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn h263_interp10_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw {
+            let a = dst[didx + x] as u16;
+            let b = ((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16) + 1) >> 1;
+            dst[didx + x] = ((a + b + 1) >> 1) as u8;
+        }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn h263_interp11_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw {
+            let a = dst[didx + x] as u16;
+            let b = ((src[sidx + x] as u16) +
+                     (src[sidx + x + 1] as u16) +
+                     (src[sidx + x + sstride] as u16) +
+                     (src[sidx + x + sstride + 1] as u16) + 2) >> 2;
+            dst[didx + x] = ((a + b + 1) >> 1) as u8;
+        }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+pub const H263_INTERP_AVG_FUNCS: &[fn(&mut [u8], usize, &[u8], usize, usize, usize)] = &[
+        h263_interp00_avg, h263_interp01_avg, h263_interp10_avg, h263_interp11_avg ];
index bb20262d5099c3e4e4dff015edbb1f4fdb0f6f3d..61e1cc43cce4a31e62bdea78b3d8cceea0ffcc8a 100644 (file)
@@ -111,6 +111,25 @@ fn decode_mv(br: &mut BitReader, mv_cb: &Codebook<u8>) -> DecoderResult<MV> {
     Ok(MV::new(xval, yval))
 }
 
+fn decode_b_info(br: &mut BitReader, is_pb: bool, is_intra: bool) -> DecoderResult<BBlockInfo> {
+    if is_pb { // as improved pb
+        let pb_mv_add = if is_intra { 1 } else { 0 };
+        if br.read_bool()?{
+            if br.read_bool()? {
+                let pb_mv_count = 1 - (br.read(1)? as usize);
+                let cbpb = br.read(6)? as u8;
+                Ok(BBlockInfo::new(true, cbpb, pb_mv_count + pb_mv_add, pb_mv_count == 1))
+            } else {
+                Ok(BBlockInfo::new(true, 0, 1 + pb_mv_add, true))
+            }
+        } else {
+            Ok(BBlockInfo::new(true, 0, pb_mv_add, false))
+        }
+    } else {
+        Ok(BBlockInfo::new(false, 0, 0, false))
+    }
+}
+
 impl<'a> BlockDecoder for Intel263BR<'a> {
 
 #[allow(unused_variables)]
@@ -162,19 +181,24 @@ impl<'a> BlockDecoder for Intel263BR<'a> {
         let quant = br.read(5)?;
         let cpm = br.read_bool()?;
         validate!(!cpm);
+
+        let pbinfo;
         if self.is_pb {
             let trb = br.read(3)?;
             let dbquant = br.read(2)?;
+            pbinfo = Some(PBInfo::new(trb as u8, dbquant as u8));
+        } else {
+            pbinfo = None;
         }
         while br.read_bool()? { // skip PEI
             br.read(8)?;
         }
-println!("frame {}x{} intra: {} q {} pb {} apm {} umv {} @{}", w, h, is_intra, quant, self.is_pb, apm, umv, br.tell());
+//println!("frame {}x{} intra: {} q {} pb {} apm {} umv {} @{}", w, h, is_intra, quant, self.is_pb, apm, umv, br.tell());
         self.gob_no = 0;
         self.mb_w = (w + 15) >> 4;
 
         let ftype = if is_intra { Type::I } else { Type::P };
-        let picinfo = PicInfo::new(w, h, ftype, quant as u8, apm, umv, self.is_pb, tr);
+        let picinfo = PicInfo::new(w, h, ftype, quant as u8, apm, umv, tr, pbinfo);
         Ok(picinfo)
     }
 
@@ -182,12 +206,11 @@ println!("frame {}x{} intra: {} q {} pb {} apm {} umv {} @{}", w, h, is_intra, q
     fn decode_slice_header(&mut self, info: &PicInfo) -> DecoderResult<Slice> {
         let mut br = &mut self.br;
         let gbsc = br.read(17)?;
-println!("GBSC = {}", gbsc);
         validate!(gbsc == 1);
         let gn = br.read(5)?;
         let gfid = br.read(2)?;
         let gquant = br.read(5)?;
-println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
+//println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
         let ret = Slice::new(0, self.gob_no, gquant as u8);
         self.gob_no += 1;
         Ok(ret)
@@ -207,11 +230,9 @@ println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
                         let idx = br.read(2)? as usize;
                         q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8;
                     }
-//println!("got cbp {:X}", cbp);
                     Ok(BlockInfo::new(Type::I, cbp, q))
                 },
             Type::P => {
-//println!("@{}",br.tell());
                     if br.read_bool()? { return Ok(BlockInfo::new(Type::Skip, 0, info.get_quant())); }
                     let mut cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?;
                     while cbpc == 20 { cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?; }
@@ -220,22 +241,7 @@ println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
                     let is_4x4   = (cbpc & 0x10) != 0;
                     if is_intra {
                         let mut mvec: Vec<MV> = Vec::new();
-                        let cbpb;
-                        let pb_mv_count: usize;
-                        if self.is_pb && br.read_bool()? {
-                            let c = br.read_bool()?;
-                            if c {
-                                pb_mv_count = 2 - (br.read(1)? as usize);
-                                cbpb = br.read(6)? as u8;
-                            } else {
-                                pb_mv_count = 2;
-                                cbpb = 0;
-                            }
-//println!("  mvc {} cbpb {:02X}", pb_mv_count, cbpb);
-                        } else {
-                            cbpb = 0;
-                            pb_mv_count = 1;
-                        }
+                        let bbinfo = decode_b_info(br, self.is_pb, true)?;
                         let cbpy = br.read_cb(&self.tables.cbpy_cb)?;
                         let cbp = (cbpy << 2) | (cbpc & 3);
                         if dquant {
@@ -243,31 +249,17 @@ println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
                             q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8;
                         }
                         let mut binfo = BlockInfo::new(Type::I, cbp, q);
+                        binfo.set_bpart(bbinfo);
                         if self.is_pb {
-                            for _ in 0..pb_mv_count {
+                            for _ in 0..bbinfo.get_num_mv() {
                                 mvec.push(decode_mv(br, &self.tables.mv_cb)?);
                             }
-                            binfo.set_mv2(cbpb, mvec.as_slice());
+                            binfo.set_b_mv(mvec.as_slice());
                         }
-//println!("@{}",br.tell());
                         return Ok(binfo);
                     }
 
-                    let cbpb;
-                    let pb_mv_count: usize;
-                    if self.is_pb && br.read_bool()?{
-                        let c = br.read_bool()?;
-                        if c {
-                            pb_mv_count = 1 - (br.read(1)? as usize);
-                            cbpb = br.read(6)? as u8;
-                        } else {
-                            pb_mv_count = 1;
-                            cbpb = 0;
-                        }
-                    } else {
-                        cbpb = 0;
-                        pb_mv_count = 0;
-                    }
+                    let bbinfo = decode_b_info(br, self.is_pb, false)?;
                     let mut cbpy = br.read_cb(&self.tables.cbpy_cb)?;
 //                    if /* !aiv && */(cbpc & 3) != 3 {
                         cbpy ^= 0xF;
@@ -278,9 +270,9 @@ println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
                         q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8;
                     }
                     let mut binfo = BlockInfo::new(Type::P, cbp, q);
+                    binfo.set_bpart(bbinfo);
                     if !is_4x4 {
                         let mvec: [MV; 1] = [decode_mv(br, &self.tables.mv_cb)?];
-//println!("@{} CBPB = {:X} mv2 {}",br.tell(), cbpb, pb_mv_count);
                         binfo.set_mv(&mvec);
                     } else {
                         let mvec: [MV; 4] = [
@@ -292,14 +284,13 @@ println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
                         binfo.set_mv(&mvec);
                     }
                     if self.is_pb {
-                        let mut mvec: Vec<MV> = Vec::with_capacity(pb_mv_count);
-                        for _ in 0..pb_mv_count {
+                        let mut mvec: Vec<MV> = Vec::with_capacity(bbinfo.get_num_mv());
+                        for _ in 0..bbinfo.get_num_mv() {
                             let mv = decode_mv(br, &self.tables.mv_cb)?;
                             mvec.push(mv);
                         }
-                        binfo.set_mv2(cbpb, mvec.as_slice());
+                        binfo.set_b_mv(mvec.as_slice());
                     }
-//println!("@{}",br.tell());
                     Ok(binfo)
                 },
             _ => { Err(DecoderError::InvalidData) },
@@ -307,13 +298,13 @@ println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
     }
 
     #[allow(unused_variables)]
-    fn decode_block_intra(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
-        self.decode_block(info.get_q(), true, coded, blk)
+    fn decode_block_intra(&mut self, info: &BlockInfo, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
+        self.decode_block(quant, true, coded, blk)
     }
 
     #[allow(unused_variables)]
-    fn decode_block_inter(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
-        self.decode_block(info.get_q(), false, coded, blk)
+    fn decode_block_inter(&mut self, info: &BlockInfo, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
+        self.decode_block(quant, false, coded, blk)
     }
 
 #[allow(unused_variables)]
@@ -370,7 +361,7 @@ impl NADecoder for Intel263Decoder {
         let src = pkt.get_buffer();
 
         if src.len() == 8 {
-            let bret = self.dec.get_stored_pframe();
+            let bret = self.dec.get_bframe();
             let buftype;
             let is_skip;
             if let Ok(btype) = bret {
@@ -382,10 +373,9 @@ impl NADecoder for Intel263Decoder {
             }
             let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype);
             frm.set_keyframe(false);
-            frm.set_frame_type(if is_skip { FrameType::Skip } else { FrameType::P });
+            frm.set_frame_type(if is_skip { FrameType::Skip } else { FrameType::B });
             return Ok(Rc::new(RefCell::new(frm)));
         }
-//println!("frame size {}", src.len());
         let mut ibr = Intel263BR::new(&src, &self.tables);
 
         let bufinfo = self.dec.parse_frame(&mut ibr)?;