preliminary work on Intel I.263
authorKostya Shishkov <kostya.shishkov@gmail.com>
Thu, 8 Jun 2017 17:26:55 +0000 (19:26 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Thu, 8 Jun 2017 17:26:55 +0000 (19:26 +0200)
src/codecs/blockdec.rs [new file with mode: 0644]
src/codecs/blockdsp.rs [new file with mode: 0644]
src/codecs/h263code.rs [new file with mode: 0644]
src/codecs/h263data.rs [new file with mode: 0644]
src/codecs/intel263.rs [new file with mode: 0644]
src/codecs/mod.rs

diff --git a/src/codecs/blockdec.rs b/src/codecs/blockdec.rs
new file mode 100644 (file)
index 0000000..0326f84
--- /dev/null
@@ -0,0 +1,440 @@
+use std::mem;
+use std::ops::Add;
+use super::*;
+use super::blockdsp;
+use super::h263code::*;
+use formats;
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum Type {
+    I, P, Skip, Special
+}
+
+#[allow(dead_code)]
+#[derive(Debug,Clone,Copy)]
+pub struct PicInfo {
+    w:      usize,
+    h:      usize,
+    mode:   Type,
+    quant:  u8,
+    apm:    bool,
+    umv:    bool,
+    pb:     bool,
+    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 get_width(&self) -> usize { self.w }
+    pub fn get_height(&self) -> usize { self.h }
+    pub fn get_mode(&self) -> Type { self.mode }
+    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 get_ts(&self) -> u8 { self.ts }
+}
+
+#[derive(Debug,Clone,Copy)]
+pub struct Slice {
+    mb_x:   usize,
+    mb_y:   usize,
+    quant:  u8,
+}
+
+impl Slice {
+    pub fn new(mb_x: usize, mb_y: usize, quant: u8) -> Self {
+        Slice{ mb_x: mb_x, mb_y: mb_y, quant: quant }
+    }
+    pub fn get_default_slice(pinfo: &PicInfo) -> Self {
+        Slice{ mb_x: 0, mb_y: 0, quant: pinfo.get_quant() }
+    }
+    pub fn get_quant(&self) -> u8 { self.quant }
+}
+
+#[derive(Debug,Clone,Copy)]
+pub struct MV {
+    x: i16,
+    y: i16,
+}
+
+impl MV {
+    pub fn new(x: i16, y: i16) -> Self { MV{ x: x, y: y } }
+    pub fn pred(a: MV, b: MV, c: MV) -> Self {
+        let x;
+        if a.x < b.x {
+            if b.x < c.x {
+                x = b.x;
+            } else {
+                if a.x < c.x { x = c.x; } else { x = a.x; }
+            }
+        } else {
+            if b.x < c.x {
+                if a.x < c.x { x = a.x; } else { x = c.x; }
+            } else {
+                x = b.x;
+            }
+        }
+        let y;
+        if a.y < b.y {
+            if b.y < c.y {
+                y = b.y;
+            } else {
+                if a.y < c.y { y = c.y; } else { y = a.y; }
+            }
+        } else {
+            if b.y < c.y {
+                if a.y < c.y { y = a.y; } else { y = c.y; }
+            } else {
+                y = b.y;
+            }
+        }
+        MV { x: x, y: y }
+    }
+    fn add_umv(pred_mv: MV, add: MV, umv: bool) -> Self {
+        let mut new_mv = pred_mv + add;
+        if umv {
+            if pred_mv.x >  32 && new_mv.x >  63 { new_mv.x -= 64; }
+            if pred_mv.x < -31 && new_mv.x < -63 { new_mv.x += 64; }
+            if pred_mv.y >  32 && new_mv.y >  63 { new_mv.y -= 64; }
+            if pred_mv.y < -31 && new_mv.y < -63 { new_mv.y += 64; }
+        } else {
+            if      new_mv.x >  31 { new_mv.x -= 64; }
+            else if new_mv.x < -32 { new_mv.x += 64; }
+            if      new_mv.y >  31 { new_mv.y -= 64; }
+            else if new_mv.y < -32 { new_mv.y += 64; }
+        }
+        new_mv
+    }
+}
+
+pub const ZERO_MV: MV = MV { x: 0, y: 0 };
+
+impl Add for MV {
+    type Output = MV;
+    fn add(self, other: MV) -> MV { MV { x: self.x + other.x, y: self.y + other.y } }
+}
+
+#[derive(Debug,Clone,Copy)]
+pub struct BlockInfo {
+    intra:   bool,
+    skip:    bool,
+    mode:    Type,
+    cbp:     u8,
+    q:       u8,
+    mv:      [MV; 4],
+    num_mv:  usize,
+    bpart:   bool,
+    b_cbp:   u8,
+    mv2:     [MV; 4],
+    num_mv2: usize,
+}
+
+#[allow(dead_code)]
+impl BlockInfo {
+    pub fn new(mode: Type, cbp: u8, q: u8) -> Self {
+        BlockInfo {
+            intra:   mode == Type::I,
+            skip:    (cbp == 0) && (mode != Type::I),
+            mode:    mode,
+            cbp:     cbp,
+            q:       q,
+            mv:      [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)],
+            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)],
+            num_mv2: 0,
+        }
+    }
+    pub fn is_intra(&self) -> bool { self.intra }
+    pub fn is_skipped(&self) -> bool { self.skip }
+    pub fn get_mode(&self) -> Type { self.mode }
+    pub fn get_cbp(&self) -> u8 { self.cbp }
+    pub fn get_q(&self) -> u8 { self.q }
+    pub fn get_num_mvs(&self) -> usize { self.num_mv }
+    pub fn get_mv(&self, idx: usize) -> MV { self.mv[idx] }
+    pub fn has_b_part(&self) -> bool { self.bpart }
+    pub fn get_cbp_b(&self) -> u8 { self.b_cbp }
+    pub fn get_num_mvs2(&self) -> usize { self.num_mv2 }
+    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)];
+        for i in 0..mvs.len() { mv_arr[i] = mvs[i]; }
+        self.mv2     = mv_arr;
+        self.num_mv2 = mvs.len();
+    }
+}
+
+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 calc_mv(&mut self, vec: MV);
+    fn is_slice_end(&mut self) -> bool;
+}
+
+#[allow(dead_code)]
+struct MVInfo {
+    mv:         Vec<MV>,
+    mb_w:       usize,
+    mb_stride:  usize,
+    mb_start:   usize,
+    top:        bool,
+    umv:        bool,
+}
+
+impl MVInfo {
+    fn new() -> Self { MVInfo{ mv: Vec::new(), mb_w: 0, mb_stride: 0, mb_start: 0, top: true, umv: false } }
+    fn reset(&mut self, mb_w: usize, mb_start: usize, umv: bool) {
+        self.mb_start  = mb_start;
+        self.mb_w      = mb_w;
+        self.mb_stride = mb_w * 2;
+        self.top       = true;
+        self.mv.resize(self.mb_stride * 3, ZERO_MV);
+        self.umv       = umv;
+    }
+    fn update_row(&mut self) {
+        self.mb_start = self.mb_w + 1;
+        self.top      = false;
+        for i in 0..self.mb_stride {
+            self.mv[i] = self.mv[self.mb_stride * 2 + i];
+        }
+    }
+    #[allow(non_snake_case)]
+    fn predict(&mut self, mb_x: usize, blk_no: usize, use4: bool, diff: MV) -> MV {
+        let A;
+        let B;
+        let C;
+        let last = mb_x == self.mb_w - 1;
+//println!("  pred from {}.{} blk {}.{}/{} top {}", diff.x, diff.y, mb_x, blk_no,self.mb_start,self.top);
+        match blk_no {
+            0 => {
+                    if mb_x != self.mb_start {
+                        A = if mb_x != 0 { self.mv[self.mb_stride + mb_x * 2 - 1] } else { ZERO_MV };
+                        B = if !self.top { self.mv[                 mb_x * 2] } else { A };
+                        C = if !self.top && !last { self.mv[mb_x * 2 + 2] } else { ZERO_MV };
+                    } else {
+                        A = ZERO_MV; B = ZERO_MV; C = ZERO_MV;
+                    }
+                },
+            1 => {
+                    A = self.mv[self.mb_stride + mb_x * 2];
+                    B = if !self.top { self.mv[mb_x * 2 + 1] } else { A };
+                    C = if !self.top && !last { self.mv[mb_x * 2 + 2] } else { A };
+                },
+            2 => {
+                    A = if mb_x != self.mb_start { self.mv[self.mb_stride * 2 + mb_x * 2 - 1] } else { ZERO_MV };
+                    B = self.mv[self.mb_stride + mb_x * 2];
+                    C = self.mv[self.mb_stride + mb_x * 2 + 1];
+                },
+            3 => {
+                    A = self.mv[self.mb_stride * 2 + mb_x * 2];
+                    B = self.mv[self.mb_stride * 1 + mb_x * 2 + 1];
+                    C = self.mv[self.mb_stride * 1 + mb_x * 2];
+                },
+            _ => { return ZERO_MV; }
+        }
+//println!("     A = {}.{}  B = {}.{}  C = {}.{}", A.x,A.y,B.x,B.y,C.x,C.y);
+        let pred_mv = MV::pred(A, B, C);
+        let new_mv = MV::add_umv(pred_mv, diff, self.umv);
+        if !use4 {
+            self.mv[self.mb_stride * 1 + mb_x * 2 + 0] = new_mv;
+            self.mv[self.mb_stride * 1 + mb_x * 2 + 1] = new_mv;
+            self.mv[self.mb_stride * 2 + mb_x * 2 + 0] = new_mv;
+            self.mv[self.mb_stride * 2 + mb_x * 2 + 1] = new_mv;
+        } else {
+            match blk_no {
+                0 => { self.mv[self.mb_stride * 1 + mb_x * 2 + 0] = new_mv; },
+                1 => { self.mv[self.mb_stride * 1 + mb_x * 2 + 1] = new_mv; },
+                2 => { self.mv[self.mb_stride * 2 + mb_x * 2 + 0] = new_mv; },
+                3 => { self.mv[self.mb_stride * 2 + mb_x * 2 + 1] = new_mv; },
+                _ => {},
+            };
+        }
+        
+        new_mv
+    }
+    fn set_zero_mv(&mut self, mb_x: usize) {
+        self.mv[self.mb_stride * 1 + mb_x * 2 + 0] = ZERO_MV;
+        self.mv[self.mb_stride * 1 + mb_x * 2 + 1] = ZERO_MV;
+        self.mv[self.mb_stride * 2 + mb_x * 2 + 0] = ZERO_MV;
+        self.mv[self.mb_stride * 2 + mb_x * 2 + 1] = ZERO_MV;
+    }
+}
+
+fn copy_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_FUNCS);
+}
+
+pub struct DCT8x8VideoDecoder {
+    w:          usize,
+    h:          usize,
+    mb_w:       usize,
+    mb_h:       usize,
+    num_mb:     usize,
+    ftype:      Type,
+    prev_frm:   Option<NAVideoBuffer<u8>>,
+    cur_frm:    Option<NAVideoBuffer<u8>>,
+}
+
+#[allow(dead_code)]
+impl DCT8x8VideoDecoder {
+    pub fn new() -> Self {
+        DCT8x8VideoDecoder{
+            w: 0, h: 0, mb_w: 0, mb_h: 0, num_mb: 0,
+            ftype: Type::Special,
+            prev_frm: None, cur_frm: None,
+        }
+    }
+
+    pub fn is_intra(&self) -> bool { self.ftype == Type::I }
+    pub fn get_dimensions(&self) -> (usize, usize) { (self.w, self.h) }
+
+    pub fn parse_frame(&mut self, bd: &mut BlockDecoder) -> DecoderResult<NABufferType> {
+        let pinfo = bd.decode_pichdr()?;
+        let mut mvi  = MVInfo::new();
+
+//todo handle res change
+        self.w = pinfo.w;
+        self.h = pinfo.h;
+        self.mb_w = (pinfo.w + 15) >> 4;
+        self.mb_h = (pinfo.h + 15) >> 4;
+        self.num_mb = self.mb_w * self.mb_h;
+        self.ftype = pinfo.mode;
+
+        mem::swap(&mut self.cur_frm, &mut self.prev_frm);
+//        if self.ftype == Type::I && !pinfo.is_pb() { self.prev_frm = None; }
+
+        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 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());
+
+        let mut blk: [[i16; 64]; 6] = [[0; 64]; 6];
+        for mb_y in 0..self.mb_h {
+            for mb_x in 0..self.mb_w {
+                for i in 0..6 { for j in 0..64 { blk[i][j] = 0; } }
+
+                if  ((mb_x != 0) || (mb_y != 0)) && bd.is_slice_end() {
+//println!("new slice @{}.{}!",mb_x,mb_y);
+                    slice = bd.decode_slice_header(&pinfo)?;
+                    mvi.reset(self.mb_w, mb_x, pinfo.get_umv());
+                }
+
+                let binfo = bd.decode_block_header(&pinfo, &slice)?;
+                let cbp = binfo.get_cbp();
+//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])?;
+                        h263_idct(&mut blk[i]);
+                    }
+                    blockdsp::put_blocks(&mut buf, mb_x, mb_y, &blk);
+                    mvi.set_zero_mv(mb_x);
+                } else if !binfo.is_skipped() {
+                    if binfo.get_num_mvs() == 1 {
+                        let mv = mvi.predict(mb_x, 0, false, binfo.get_mv(0));
+//println!(" 1MV {}.{}", mv.x, mv.y);
+                        if let Some(ref srcbuf) = self.prev_frm {
+                            copy_blocks(&mut buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, mv);
+                        }
+                    } else {
+                        for blk_no in 0..4 {
+                            let mv = mvi.predict(mb_x, blk_no, true, binfo.get_mv(blk_no));
+//print!(" MV {}.{}", mv.x, mv.y);
+                            if let Some(ref srcbuf) = self.prev_frm {
+                                copy_blocks(&mut buf, srcbuf,
+                                            mb_x * 16 + (blk_no & 1) * 8,
+                                            mb_y * 16 + (blk_no & 2) * 4, 8, 8, mv);
+                            }
+                        }
+//println!("");
+                    }
+                    for i in 0..6 {
+                        bd.decode_block_inter(&binfo, i, ((cbp >> (5 - i)) & 1) != 0, &mut blk[i])?;
+                        h263_idct(&mut blk[i]);
+                    }
+                    blockdsp::add_blocks(&mut buf, mb_x, mb_y, &blk);
+                } else {
+                    mvi.set_zero_mv(mb_x);
+                    if let Some(ref srcbuf) = self.prev_frm {
+                        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];
+                    let cbp = binfo.get_cbp_b();
+                    for i in 0..6 {
+                        bd.decode_block_inter(&binfo, i, (cbp & (1 << (5 - i))) != 0, &mut blk[i])?;
+                        h263_idct(&mut 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);
+                        }
+                    }
+                }
+
+            }
+            mvi.update_row();
+        }
+        self.cur_frm = Some(buf);
+        if pinfo.is_pb() {
+            return Ok(NABufferType::Video(bbuf.unwrap()));
+        } 
+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)
+        }
+    }
+}
diff --git a/src/codecs/blockdsp.rs b/src/codecs/blockdsp.rs
new file mode 100644 (file)
index 0000000..2f02b84
--- /dev/null
@@ -0,0 +1,186 @@
+use frame::*;
+
+pub fn put_blocks(buf: &mut NAVideoBuffer<u8>, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) {
+    let stridey = buf.get_stride(0);
+    let strideu = buf.get_stride(1);
+    let stridev = buf.get_stride(2);
+    let mut idxy = buf.get_offset(0) + xpos * 16 + ypos * 16 * stridey;
+    let mut idxu = buf.get_offset(1) + xpos *  8 + ypos *  8 * strideu;
+    let mut idxv = buf.get_offset(2) + xpos *  8 + ypos *  8 * stridev;
+
+    let mut data = buf.get_data_mut();
+    let mut framebuf: &mut [u8] = data.as_mut_slice();
+
+    for j in 0..8 {
+        for k in 0..8 {
+            let mut v = blk[0][k + j * 8];
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k] = v as u8;
+        }
+        for k in 0..8 {
+            let mut v = blk[1][k + j * 8];
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k + 8] = v as u8;
+        }
+        idxy += stridey;
+    }
+    for j in 0..8 {
+        for k in 0..8 {
+            let mut v = blk[2][k + j * 8];
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k] = v as u8;
+        }
+        for k in 0..8 {
+            let mut v = blk[3][k + j * 8];
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k + 8] = v as u8;
+        }
+        idxy += stridey;
+    }
+
+    for j in 0..8 {
+        for k in 0..8 {
+            let mut v = blk[4][k + j * 8];
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxu + k] = v as u8;
+        }
+        for k in 0..8 {
+            let mut v = blk[5][k + j * 8];
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxv + k] = v as u8;
+        }
+        idxu += strideu;
+        idxv += stridev;
+    }
+}
+
+pub fn add_blocks(buf: &mut NAVideoBuffer<u8>, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) {
+    let stridey = buf.get_stride(0);
+    let strideu = buf.get_stride(1);
+    let stridev = buf.get_stride(2);
+    let mut idxy = buf.get_offset(0) + xpos * 16 + ypos * 16 * stridey;
+    let mut idxu = buf.get_offset(1) + xpos *  8 + ypos *  8 * strideu;
+    let mut idxv = buf.get_offset(2) + xpos *  8 + ypos *  8 * stridev;
+
+    let mut data = buf.get_data_mut();
+    let mut framebuf: &mut [u8] = data.as_mut_slice();
+
+    for j in 0..8 {
+        for k in 0..8 {
+            let mut v = blk[0][k + j * 8] + (framebuf[idxy + k] as i16);
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k] = v as u8;
+        }
+        for k in 0..8 {
+            let mut v = blk[1][k + j * 8] + (framebuf[idxy + k + 8] as i16);
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k + 8] = v as u8;
+        }
+        idxy += stridey;
+    }
+    for j in 0..8 {
+        for k in 0..8 {
+            let mut v = blk[2][k + j * 8] + (framebuf[idxy + k] as i16);
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k] = v as u8;
+        }
+        for k in 0..8 {
+            let mut v = blk[3][k + j * 8] + (framebuf[idxy + k + 8] as i16);
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxy + k + 8] = v as u8;
+        }
+        idxy += stridey;
+    }
+
+    for j in 0..8 {
+        for k in 0..8 {
+            let mut v = blk[4][k + j * 8] + (framebuf[idxu + k] as i16);
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxu + k] = v as u8;
+        }
+        for k in 0..8 {
+            let mut v = blk[5][k + j * 8] + (framebuf[idxv + k] as i16);
+            if v < 0 { v = 0; } if v > 255 { v = 255; }
+            framebuf[idxv + k] = v as u8;
+        }
+        idxu += strideu;
+        idxv += stridev;
+    }
+}
+
+fn edge_emu(src: &NAVideoBuffer<u8>, xpos: isize, ypos: isize, bw: usize, bh: usize, dst: &mut [u8], dstride: usize, comp: usize) {
+    let stride = src.get_stride(comp);
+    let offs   = src.get_offset(comp);
+    let (w, h) = src.get_dimensions(comp);
+    let data = src.get_data();
+    let framebuf: &[u8] = data.as_slice();
+
+    for y in 0..bh {
+        let srcy;
+        if (y as isize) + ypos < 0 { srcy = 0; }
+        else if (y as isize) + ypos >= (h as isize) { srcy = h - 1; }
+        else { srcy = ((y as isize) + ypos) as usize; }
+
+        for x in 0..bw {
+            let srcx;
+            if (x as isize) + xpos < 0 { srcx = 0; }
+            else if (x as isize) + xpos >= (w as isize) { srcx = w - 1; }
+            else { srcx = ((x as isize) + xpos) as usize; }
+            dst[x + y * dstride] = framebuf[offs + srcx + srcy * stride];
+        }
+    }
+}
+
+pub fn copy_blocks(dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>,
+                   dx: usize, dy: usize, sx: isize, sy: isize, bw: usize, bh: usize,
+                   preborder: usize, postborder: usize,
+                   mode: usize, interp: &[fn(&mut [u8], usize, &[u8], usize, usize, usize)])
+{
+    let pre  = if mode != 0 { preborder  as isize } else { 0 };
+    let post = if mode != 0 { postborder as isize } else { 0 };
+    let (w, h) = src.get_dimensions(0);
+
+    if (sx - pre < 0) || ((sx >> 1) - pre < 0) || (sx + (bw as isize) + post > (w as isize)) ||
+       (sy - pre < 0) || ((sy >> 1) - pre < 0) || (sy + (bh as isize) + post > (h as isize)) {
+        let ebuf_stride: usize = 32;
+        let mut ebuf: Vec<u8> = Vec::with_capacity(ebuf_stride * (bh + ((pre + post) as usize)));
+        ebuf.resize((((pre + post) as usize) + bh) * ebuf_stride, 0);
+
+        for comp in 0..3 {
+            let dstride = src.get_stride(comp);
+            let doff    = dst.get_offset(comp);
+            let mut ddta    = dst.get_data_mut();
+            let mut dbuf: &mut [u8] = ddta.as_mut_slice();
+            let x   = if comp > 0 { dx/2 } else { dx };
+            let y   = if comp > 0 { dy/2 } else { dy };
+            let sx_ = (if comp > 0 { sx >> 1 } else { sx }) - pre;
+            let sy_ = (if comp > 0 { sy >> 1 } else { sy }) - pre;
+            let bw_ = (if comp > 0 { bw/2 } else { bw }) + ((pre + post) as usize);
+            let bh_ = (if comp > 0 { bh/2 } else { bh }) + ((pre + post) as usize);
+            edge_emu(src, sx_ - pre, sy_ - pre, bw_, bh_,
+                     ebuf.as_mut_slice(), ebuf_stride, comp);
+            let bw_ = if comp > 0 { bw/2 } else { bw };
+            let bh_ = if comp > 0 { bh/2 } else { bh };
+            (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, ebuf.as_slice(), ebuf_stride, bw_, bh_);
+        }
+        
+    } else {
+        for comp in 0..3 {
+            let sstride = src.get_stride(comp);
+            let soff    = src.get_offset(comp);
+            let sdta    = src.get_data();
+            let sbuf: &[u8] = sdta.as_slice();
+            let dstride = src.get_stride(comp);
+            let doff    = dst.get_offset(comp);
+            let mut ddta    = dst.get_data_mut();
+            let mut dbuf: &mut [u8] = ddta.as_mut_slice();
+            let x   = if comp > 0 { dx/2 } else { dx };
+            let y   = if comp > 0 { dy/2 } else { dy };
+            let sx_ = ((if comp > 0 { sx >> 1 } else { sx }) - pre) as usize;
+            let sy_ = ((if comp > 0 { sy >> 1 } else { sy }) - pre) as usize;
+            let bw_ = if comp > 0 { bw/2 } else { bw };
+            let bh_ = if comp > 0 { bh/2 } else { bh };
+            (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, &sbuf[(soff + sx_ + sy_ * sstride)..], sstride, bw_, bh_);
+        }
+    }
+}
diff --git a/src/codecs/h263code.rs b/src/codecs/h263code.rs
new file mode 100644 (file)
index 0000000..d38af95
--- /dev/null
@@ -0,0 +1,269 @@
+//use super::h263data::*;
+
+/*const W1: i32 = 22725;
+const W2: i32 = 21407;
+const W3: i32 = 19266;
+const W4: i32 = 16383;
+const W5: i32 = 12873;
+const W6: i32 =  8867;
+const W7: i32 =  4520;
+
+const ROW_SHIFT: u8 = 11;
+const COL_SHIFT: u8 = 20;
+
+fn idct_row(row: &mut [i16]) {
+    let in0 = row[0] as i32;
+    let in1 = row[1] as i32;
+    let in2 = row[2] as i32;
+    let in3 = row[3] as i32;
+    let in4 = row[4] as i32;
+    let in5 = row[5] as i32;
+    let in6 = row[6] as i32;
+    let in7 = row[7] as i32;
+
+    let mut a0 = in0 * W1 + (1 << (ROW_SHIFT - 1));
+    let mut a1 = a0;
+    let mut a2 = a0;
+    let mut a3 = a0;
+
+    a0 += W2 * in2;
+    a1 += W6 * in2;
+    a2 -= W6 * in2;
+    a3 -= W2 * in2;
+
+    let mut b0 = W1 * in1 + W3 * in3;
+    let mut b1 = W3 * in1 - W7 * in3;
+    let mut b2 = W5 * in1 - W1 * in3;
+    let mut b3 = W7 * in1 - W5 * in3;
+
+    a0 += W4 * in4 + W6 * in6;
+    a1 -= W4 * in4 + W2 * in6;
+    a2 -= W4 * in4 - W2 * in6;
+    a3 += W4 * in4 - W6 * in6;
+
+    b0 += W5 * in5 + W7 * in7;
+    b1 -= W1 * in5 + W5 * in7;
+    b2 += W7 * in5 + W3 * in7;
+    b3 += W3 * in5 - W1 * in7;
+
+    row[0] = ((a0 + b0) >> ROW_SHIFT) as i16;
+    row[7] = ((a0 - b0) >> ROW_SHIFT) as i16;
+    row[1] = ((a1 + b1) >> ROW_SHIFT) as i16;
+    row[6] = ((a1 - b1) >> ROW_SHIFT) as i16;
+    row[2] = ((a2 + b2) >> ROW_SHIFT) as i16;
+    row[5] = ((a2 - b2) >> ROW_SHIFT) as i16;
+    row[3] = ((a3 + b3) >> ROW_SHIFT) as i16;
+    row[4] = ((a3 - b3) >> ROW_SHIFT) as i16;
+}
+
+fn idct_col(blk: &mut [i16; 64], off: usize) {
+    let in0 = blk[off + 0*8] as i32;
+    let in1 = blk[off + 1*8] as i32;
+    let in2 = blk[off + 2*8] as i32;
+    let in3 = blk[off + 3*8] as i32;
+    let in4 = blk[off + 4*8] as i32;
+    let in5 = blk[off + 5*8] as i32;
+    let in6 = blk[off + 6*8] as i32;
+    let in7 = blk[off + 7*8] as i32;
+
+    let mut a0 = in0 * W1 + (1 << (COL_SHIFT - 1));
+    let mut a1 = a0;
+    let mut a2 = a0;
+    let mut a3 = a0;
+
+    a0 += W2 * in2;
+    a1 += W6 * in2;
+    a2 -= W6 * in2;
+    a3 -= W2 * in2;
+
+    let mut b0 = W1 * in1 + W3 * in3;
+    let mut b1 = W3 * in1 - W7 * in3;
+    let mut b2 = W5 * in1 - W1 * in3;
+    let mut b3 = W7 * in1 - W5 * in3;
+
+    a0 += W4 * in4 + W6 * in6;
+    a1 -= W4 * in4 + W2 * in6;
+    a2 -= W4 * in4 - W2 * in6;
+    a3 += W4 * in4 - W6 * in6;
+
+    b0 += W5 * in5 + W7 * in7;
+    b1 -= W1 * in5 + W5 * in7;
+    b2 += W7 * in5 + W3 * in7;
+    b3 += W3 * in5 - W1 * in7;
+
+    blk[off + 0*8] = ((a0 + b0) >> COL_SHIFT) as i16;
+    blk[off + 7*8] = ((a0 - b0) >> COL_SHIFT) as i16;
+    blk[off + 1*8] = ((a1 + b1) >> COL_SHIFT) as i16;
+    blk[off + 6*8] = ((a1 - b1) >> COL_SHIFT) as i16;
+    blk[off + 2*8] = ((a2 + b2) >> COL_SHIFT) as i16;
+    blk[off + 5*8] = ((a2 - b2) >> COL_SHIFT) as i16;
+    blk[off + 3*8] = ((a3 + b3) >> COL_SHIFT) as i16;
+    blk[off + 4*8] = ((a3 - b3) >> COL_SHIFT) as i16;
+}
+
+#[allow(dead_code)]
+pub fn h263_idct(blk: &mut [i16; 64]) {
+    for i in 0..8 { idct_row(&mut blk[i*8..(i+1)*8]); }
+    for i in 0..8 { idct_col(blk, i); }
+}*/
+
+const W1: i32 = 2841;
+const W2: i32 = 2676;
+const W3: i32 = 2408;
+const W5: i32 = 1609;
+const W6: i32 = 1108;
+const W7: i32 =  565;
+const W8: i32 =  181;
+
+const ROW_SHIFT: u8 = 8;
+const COL_SHIFT: u8 = 14;
+
+fn idct_row(row: &mut [i16]) {
+    let in0 = ((row[0] as i32) << 11) + (1 << (ROW_SHIFT - 1));
+    let in1 =  (row[4] as i32) << 11;
+    let in2 =   row[6] as i32;
+    let in3 =   row[2] as i32;
+    let in4 =   row[1] as i32;
+    let in5 =   row[7] as i32;
+    let in6 =   row[5] as i32;
+    let in7 =   row[3] as i32;
+
+    let tmp = W7 * (in4 + in5);
+    let a4 = tmp + (W1 - W7) * in4;
+    let a5 = tmp - (W1 + W7) * in5;
+
+    let tmp = W3 * (in6 + in7);
+    let a6 = tmp - (W3 - W5) * in6;
+    let a7 = tmp - (W3 + W5) * in7;
+
+    let tmp = in0 + in1;
+
+    let a0 = in0 - in1;
+    let t1 = W6 * (in2 + in3);
+    let a2 = t1 - (W2 + W6) * in2;
+    let a3 = t1 + (W2 - W6) * in3;
+    let b1 = a4 + a6;
+
+    let b4 = a4 - a6;
+    let t2 = a5 - a7;
+    let b6 = a5 + a7;
+    let b7 = tmp + a3;
+    let b5 = tmp - a3;
+    let b3 = a0 + a2;
+    let b0 = a0 - a2;
+    let b2 = (W8 * (b4 + t2) + 128) >> 8;
+    let b4 = (W8 * (b4 - t2) + 128) >> 8;
+
+    row[0] = ((b7 + b1) >> ROW_SHIFT) as i16;
+    row[7] = ((b7 - b1) >> ROW_SHIFT) as i16;
+    row[1] = ((b3 + b2) >> ROW_SHIFT) as i16;
+    row[6] = ((b3 - b2) >> ROW_SHIFT) as i16;
+    row[2] = ((b0 + b4) >> ROW_SHIFT) as i16;
+    row[5] = ((b0 - b4) >> ROW_SHIFT) as i16;
+    row[3] = ((b5 + b6) >> ROW_SHIFT) as i16;
+    row[4] = ((b5 - b6) >> ROW_SHIFT) as i16;
+}
+
+fn idct_col(blk: &mut [i16; 64], off: usize) {
+    let in0 = ((blk[off + 0*8] as i32) << 8) + (1 << (COL_SHIFT - 1));
+    let in1 =  (blk[off + 4*8] as i32) << 8;
+    let in2 =   blk[off + 6*8] as i32;
+    let in3 =   blk[off + 2*8] as i32;
+    let in4 =   blk[off + 1*8] as i32;
+    let in5 =   blk[off + 7*8] as i32;
+    let in6 =   blk[off + 5*8] as i32;
+    let in7 =   blk[off + 3*8] as i32;
+
+    let tmp = W7 * (in4 + in5);
+    let a4 = (tmp + (W1 - W7) * in4) >> 3;
+    let a5 = (tmp - (W1 + W7) * in5) >> 3;
+
+    let tmp = W3 * (in6 + in7);
+    let a6 = (tmp - (W3 - W5) * in6) >> 3;
+    let a7 = (tmp - (W3 + W5) * in7) >> 3;
+
+    let tmp = in0 + in1;
+
+    let a0 = in0 - in1;
+    let t1 = W6 * (in2 + in3);
+    let a2 = (t1 - (W2 + W6) * in2) >> 3;
+    let a3 = (t1 + (W2 - W6) * in3) >> 3;
+    let b1 = a4 + a6;
+
+    let b4 = a4 - a6;
+    let t2 = a5 - a7;
+    let b6 = a5 + a7;
+    let b7 = tmp + a3;
+    let b5 = tmp - a3;
+    let b3 = a0 + a2;
+    let b0 = a0 - a2;
+    let b2 = (W8 * (b4 + t2) + 128) >> 8;
+    let b4 = (W8 * (b4 - t2) + 128) >> 8;
+
+    blk[off + 0*8] = ((b7 + b1) >> COL_SHIFT) as i16;
+    blk[off + 7*8] = ((b7 - b1) >> COL_SHIFT) as i16;
+    blk[off + 1*8] = ((b3 + b2) >> COL_SHIFT) as i16;
+    blk[off + 6*8] = ((b3 - b2) >> COL_SHIFT) as i16;
+    blk[off + 2*8] = ((b0 + b4) >> COL_SHIFT) as i16;
+    blk[off + 5*8] = ((b0 - b4) >> COL_SHIFT) as i16;
+    blk[off + 3*8] = ((b5 + b6) >> COL_SHIFT) as i16;
+    blk[off + 4*8] = ((b5 - b6) >> COL_SHIFT) as i16;
+}
+
+#[allow(dead_code)]
+pub fn h263_idct(blk: &mut [i16; 64]) {
+    for i in 0..8 { idct_row(&mut blk[i*8..(i+1)*8]); }
+    for i in 0..8 { idct_col(blk, i); }
+}
+
+fn h263_interp00(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 { dst[didx + x] = src[sidx + x]; }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn h263_interp01(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 { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + 1] as u16) + 1) >> 1) as u8; }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn h263_interp10(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 { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16) + 1) >> 1) as u8; }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn h263_interp11(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 {
+            dst[didx + x] = (((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) as u8;
+        }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+pub const H263_INTERP_FUNCS: &[fn(&mut [u8], usize, &[u8], usize, usize, usize)] = &[
+        h263_interp00, h263_interp01, h263_interp10, h263_interp11 ];
diff --git a/src/codecs/h263data.rs b/src/codecs/h263data.rs
new file mode 100644 (file)
index 0000000..76c3c43
--- /dev/null
@@ -0,0 +1,148 @@
+use io::codebook::CodebookDescReader;
+
+#[allow(dead_code)]
+pub const H263_SCALES: &[u8] = &[
+    0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15 ];
+
+pub const H263_ZIGZAG: &[usize] = &[
+    0,   1,  8, 16,  9,  2,  3, 10,
+    17, 24, 32, 25, 18, 11,  4,  5,
+    12, 19, 26, 33, 40, 48, 41, 34,
+    27, 20, 13,  6,  7, 14, 21, 28,
+    35, 42, 49, 56, 57, 50, 43, 36,
+    29, 22, 15, 23, 30, 37, 44, 51,
+    58, 59, 52, 45, 38, 31, 39, 46,
+    53, 60, 61, 54, 47, 55, 62, 63
+];
+
+pub const H263_SIZES: &[(usize, usize)] = &[
+    (0, 0), (128, 96), (176, 144), (352, 288), (704, 576), (1408, 1152)
+];
+
+pub const H263_INTRA_MCBPC: &[(u8, u8)] = &[
+    (1, 1), (1, 3), (2, 3), (3, 3), (1, 4), (1, 6), (2, 6), (3, 6), (1, 9)
+];
+
+pub const H263_INTER_MCBPC: &[(u8, u8)] = &[
+    (1, 1), (3, 4), (2, 4), (5, 6), (3, 5), (4, 8), (3, 8), (3, 7),
+    (3, 3), (7, 7), (6, 7), (5, 9), (4, 6), (4, 9), (3, 9), (2, 9),
+    (2, 3), (5, 7), (4, 7), (5, 8), (1, 9), (0, 0), (0, 0), (0, 0),
+    (2, 11), (12, 13), (14, 13), (15, 13)
+];
+
+pub const H263_CBPY: &[(u8, u8)] = &[
+    ( 3, 4), ( 5, 5), ( 4, 5), ( 9, 4), ( 3, 5), ( 7, 4), ( 2, 6), (11, 4),
+    ( 2, 5), ( 3, 6), ( 5, 4), (10, 4), ( 4, 4), ( 8, 4), ( 6, 4), ( 3, 2)
+];
+
+pub const H263_MV: &[(u8, u8)] = &[
+    ( 1,  1), ( 1,  2), ( 1,  3), ( 1,  4), ( 3,  6), ( 5,  7), ( 4,  7), ( 3,  7),
+    (11,  9), (10,  9), ( 9,  9), (17, 10), (16, 10), (15, 10), (14, 10), (13, 10),
+    (12, 10), (11, 10), (10, 10), ( 9, 10), ( 8, 10), ( 7, 10), ( 6, 10), ( 5, 10),
+    ( 4, 10), ( 7, 11), ( 6, 11), ( 5, 11), ( 4, 11), ( 3, 11), ( 2, 11), ( 3, 12),
+    ( 2, 12)
+];
+
+pub const H263_DQUANT_TAB: &[i8] = &[-1, -2, 1, 2];
+
+pub struct H263ShortCodeReader { tab: &'static [(u8, u8)] }
+
+impl H263ShortCodeReader {
+    pub fn new(tab: &'static [(u8, u8)]) -> Self { H263ShortCodeReader { tab: tab } }
+}
+
+impl CodebookDescReader<u8> for H263ShortCodeReader {
+    fn bits(&mut self, idx: usize) -> u8  { let (_, bits) = self.tab[idx]; bits }
+    fn code(&mut self, idx: usize) -> u32 { let (code, _) = self.tab[idx]; code as u32 }
+    fn sym (&mut self, idx: usize) -> u8 { idx as u8 }
+    fn len(&mut self) -> usize { self.tab.len() }
+}
+
+#[derive(Clone,Copy)]
+pub struct H263RLSym { run: u8, level: i8 }
+impl H263RLSym {
+    pub fn get_run(&self)   -> u8 { self.run }
+    pub fn is_last(&self)   -> bool { self.level < 0 }
+    pub fn is_escape(&self) -> bool { (self.run == 0) && (self.level == 0) }
+    pub fn get_level(&self) -> i16 { if self.level < 0 { -self.level as i16 } else { self.level as i16 } }
+}
+
+pub struct H263RLCodeDesc { code: u8, bits: u8, sym: H263RLSym }
+
+macro_rules! rlcodes{
+    ($(($c:expr, $b:expr, $r:expr, $l:expr)),*) => {
+        &[$(H263RLCodeDesc{ code: $c, bits: $b, sym: H263RLSym{ run: $r, level: $l }}),*]
+    }
+}
+
+pub const H263_RL_CODES: &[H263RLCodeDesc] = rlcodes!(
+    (0x02,  2,  0,  1), (0x0F,  4,  0,  2), (0x15,  6,  0,  3), (0x17,  7,  0,  4),
+    (0x1F,  8,  0,  5), (0x25,  9,  0,  6), (0x24,  9,  0,  7), (0x21, 10,  0,  8),
+    (0x20, 10,  0,  9), (0x07, 11,  0, 10), (0x06, 11,  0, 11), (0x20, 11,  0, 12),
+    (0x06,  3,  1,  1), (0x14,  6,  1,  2), (0x1E,  8,  1,  3), (0x0F, 10,  1,  4),
+    (0x21, 11,  1,  5), (0x50, 12,  1,  6), (0x0E,  4,  2,  1), (0x1D,  8,  2,  2),
+    (0x0E, 10,  2,  3), (0x51, 12,  2,  4), (0x0D,  5,  3,  1), (0x23,  9,  3,  2),
+    (0x0D, 10,  3,  3), (0x0C,  5,  4,  1), (0x22,  9,  4,  2), (0x52, 12,  4,  3),
+    (0x0B,  5,  5,  1), (0x0C, 10,  5,  2), (0x53, 12,  5,  3), (0x13,  6,  6,  1),
+    (0x0B, 10,  6,  2), (0x54, 12,  6,  3), (0x12,  6,  7,  1), (0x0A, 10,  7,  2),
+    (0x11,  6,  8,  1), (0x09, 10,  8,  2), (0x10,  6,  9,  1), (0x08, 10,  9,  2),
+    (0x16,  7, 10,  1), (0x55, 12, 10,  2), (0x15,  7, 11,  1), (0x14,  7, 12,  1),
+    (0x1C,  8, 13,  1), (0x1B,  8, 14,  1), (0x21,  9, 15,  1), (0x20,  9, 16,  1),
+    (0x1F,  9, 17,  1), (0x1E,  9, 18,  1), (0x1D,  9, 19,  1), (0x1C,  9, 20,  1),
+    (0x1B,  9, 21,  1), (0x1A,  9, 22,  1), (0x22, 11, 23,  1), (0x23, 11, 24,  1),
+    (0x56, 12, 25,  1), (0x57, 12, 26,  1), (0x07,  4,  0, -1), (0x19,  9,  0, -2),
+    (0x05, 11,  0, -3), (0x0F,  6,  1, -1), (0x04, 11,  1, -2), (0x0E,  6,  2, -1),
+    (0x0D,  6,  3, -1), (0x0C,  6,  4, -1), (0x13,  7,  5, -1), (0x12,  7,  6, -1),
+    (0x11,  7,  7, -1), (0x10,  7,  8, -1), (0x1A,  8,  9, -1), (0x19,  8, 10, -1),
+    (0x18,  8, 11, -1), (0x17,  8, 12, -1), (0x16,  8, 13, -1), (0x15,  8, 14, -1),
+    (0x14,  8, 15, -1), (0x13,  8, 16, -1), (0x18,  9, 17, -1), (0x17,  9, 18, -1),
+    (0x16,  9, 19, -1), (0x15,  9, 20, -1), (0x14,  9, 21, -1), (0x13,  9, 22, -1),
+    (0x12,  9, 23, -1), (0x11,  9, 24, -1), (0x07, 10, 25, -1), (0x06, 10, 26, -1),
+    (0x05, 10, 27, -1), (0x04, 10, 28, -1), (0x24, 11, 29, -1), (0x25, 11, 30, -1),
+    (0x26, 11, 31, -1), (0x27, 11, 32, -1), (0x58, 12, 33, -1), (0x59, 12, 34, -1),
+    (0x5A, 12, 35, -1), (0x5B, 12, 36, -1), (0x5C, 12, 37, -1), (0x5D, 12, 38, -1),
+    (0x5E, 12, 39, -1), (0x5F, 12, 40, -1), (0x03,  7,  0,  0)
+);
+
+pub const H263_RL_CODES_AIC: &[H263RLCodeDesc] = rlcodes!(
+    (0x02,  2,  0,  1), (0x06,  3,  0,  2), (0x0E,  4,  0,  3), (0x0C,  5,  0,  4),
+    (0x0D,  5,  0,  5), (0x10,  6,  0,  6), (0x11,  6,  0,  7), (0x12,  6,  0,  8),
+    (0x16,  7,  0,  9), (0x1B,  8,  0, 10), (0x20,  9,  0, 11), (0x21,  9,  0, 12),
+    (0x1A,  9,  0, 13), (0x1B,  9,  0, 14), (0x1C,  9,  0, 15), (0x1D,  9,  0, 16),
+    (0x1E,  9,  0, 17), (0x1F,  9,  0, 18), (0x23, 11,  0, 19), (0x22, 11,  0, 20),
+    (0x57, 12,  0, 21), (0x56, 12,  0, 22), (0x55, 12,  0, 23), (0x54, 12,  0, 24),
+    (0x53, 12,  0, 25), (0x0F,  4,  1,  1), (0x14,  6,  1,  2), (0x14,  7,  1,  3),
+    (0x1E,  8,  1,  4), (0x0F, 10,  1,  5), (0x21, 11,  1,  6), (0x50, 12,  1,  7),
+    (0x0B,  5,  2,  1), (0x15,  7,  2,  2), (0x0E, 10,  2,  3), (0x09, 10,  2,  4),
+    (0x15,  6,  3,  1), (0x1D,  8,  3,  2), (0x0D, 10,  3,  3), (0x51, 12,  3,  4),
+    (0x13,  6,  4,  1), (0x23,  9,  4,  2), (0x07, 11,  4,  3), (0x17,  7,  5,  1),
+    (0x22,  9,  5,  2), (0x52, 12,  5,  3), (0x1C,  8,  6,  1), (0x0C, 10,  6,  2),
+    (0x1F,  8,  7,  1), (0x0B, 10,  7,  2), (0x25,  9,  8,  1), (0x0A, 10,  8,  2),
+    (0x24,  9,  9,  1), (0x06, 11,  9,  2), (0x21, 10, 10,  1), (0x20, 10, 11,  1),
+    (0x08, 10, 12,  1), (0x20, 11, 13,  1), (0x07,  4,  0, -1), (0x0C,  6,  0, -2),
+    (0x10,  7,  0, -3), (0x13,  8,  0, -4), (0x11,  9,  0, -5), (0x12,  9,  0, -6),
+    (0x04, 10,  0, -7), (0x27, 11,  0, -8), (0x26, 11,  0, -9), (0x5F, 12,  0,-10),
+    (0x0F,  6,  1, -1), (0x13,  9,  1, -2), (0x05, 10,  1, -3), (0x25, 11,  1, -4),
+    (0x0E,  6,  2, -1), (0x14,  9,  2, -2), (0x24, 11,  2, -3), (0x0D,  6,  3, -1),
+    (0x06, 10,  3, -2), (0x5E, 12,  3, -3), (0x11,  7,  4, -1), (0x07, 10,  4, -2),
+    (0x13,  7,  5, -1), (0x5D, 12,  5, -2), (0x12,  7,  6, -1), (0x5C, 12,  6, -2),
+    (0x14,  8,  7, -1), (0x5B, 12,  7, -2), (0x15,  8,  8, -1), (0x1A,  8,  9, -1),
+    (0x19,  8, 10, -1), (0x18,  8, 11, -1), (0x17,  8, 12, -1), (0x16,  8, 13, -1),
+    (0x19,  9, 14, -1), (0x15,  9, 15, -1), (0x16,  9, 16, -1), (0x18,  9, 17, -1),
+    (0x17,  9, 18, -1), (0x04, 11, 19, -1), (0x05, 11, 20, -1), (0x58, 12, 21, -1),
+    (0x59, 12, 22, -1), (0x5A, 12, 23, -1), (0x03,  7,  0,  0)
+);
+
+pub struct H263RLCodeReader { tab: &'static [H263RLCodeDesc] }
+
+impl H263RLCodeReader {
+    pub fn new(tab: &'static [H263RLCodeDesc]) -> Self { H263RLCodeReader { tab: tab } }
+}
+
+impl CodebookDescReader<H263RLSym> for H263RLCodeReader {
+    fn bits(&mut self, idx: usize) -> u8  { self.tab[idx].bits }
+    fn code(&mut self, idx: usize) -> u32 { self.tab[idx].code as u32 }
+    fn sym (&mut self, idx: usize) -> H263RLSym { self.tab[idx].sym }
+    fn len(&mut self) -> usize { self.tab.len() }
+}
+
diff --git a/src/codecs/intel263.rs b/src/codecs/intel263.rs
new file mode 100644 (file)
index 0000000..bb20262
--- /dev/null
@@ -0,0 +1,452 @@
+use io::bitreader::*;
+use io::codebook::*;
+use formats;
+use super::*;
+use super::blockdec::*;
+use super::h263data::*;
+
+#[allow(dead_code)]
+struct Tables {
+    intra_mcbpc_cb: Codebook<u8>,
+    inter_mcbpc_cb: Codebook<u8>,
+    cbpy_cb:        Codebook<u8>,
+    rl_cb:          Codebook<H263RLSym>,
+    aic_rl_cb:      Codebook<H263RLSym>,
+    mv_cb:          Codebook<u8>,
+}
+
+struct Intel263Decoder {
+    info:    Rc<NACodecInfo>,
+    dec:     DCT8x8VideoDecoder,
+    tables:  Tables,
+}
+
+struct Intel263BR<'a> {
+    br:     BitReader<'a>,
+    tables: &'a Tables,
+    gob_no: usize,
+    mb_w:   usize,
+    is_pb:  bool,
+}
+
+fn check_marker<'a>(br: &mut BitReader<'a>) -> DecoderResult<()> {
+    let mark = br.read(1)?;
+    validate!(mark == 1);
+    Ok(())
+}
+
+impl<'a> Intel263BR<'a> {
+    fn new(src: &'a [u8], tables: &'a Tables) -> Self {
+        Intel263BR {
+            br:     BitReader::new(src, src.len(), BitReaderMode::BE),
+            tables: tables,
+            gob_no: 0,
+            mb_w:   0,
+            is_pb:  false,
+        }
+    }
+
+    fn decode_block(&mut self, quant: u8, intra: bool, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
+        let mut br = &mut self.br;
+        let mut idx = 0;
+        if intra {
+            let mut dc = br.read(8)?;
+            if dc == 255 { dc = 128; }
+            blk[0] = (dc as i16) << 3;
+            idx = 1;
+        }
+        if !coded { return Ok(()); }
+
+        let rl_cb = &self.tables.rl_cb; // could be aic too
+        let q_add = if quant == 0 { 0i16 } else { ((quant - 1) | 1) as i16 };
+        let q = (quant * 2) as i16;
+        while idx < 64 {
+            let code = br.read_cb(rl_cb)?;
+            let run;
+            let mut level;
+            let last;
+            if !code.is_escape() {
+                run   = code.get_run();
+                level = code.get_level();
+                last  = code.is_last();
+                if br.read_bool()? { level = -level; }
+                level = (level * q) + q_add;
+            } else {
+                last  = br.read_bool()?;
+                run   = br.read(6)? as u8;
+                level = br.read_s(8)? as i16;
+                if level == -128 {
+                    let low = br.read(5)? as i16;
+                    let top = br.read_s(6)? as i16;
+                    level = (top << 5) | low;
+                }
+                level = (level * q) + q_add;
+                if level < -2048 { level = -2048; }
+                if level >  2047 { level =  2047; }
+            }
+            idx += run;
+            validate!(idx < 64);
+            let oidx = H263_ZIGZAG[idx as usize];
+            blk[oidx] = level;
+            idx += 1;
+            if last { break; }
+        }
+        Ok(())
+    }
+}
+
+fn decode_mv_component(br: &mut BitReader, mv_cb: &Codebook<u8>) -> DecoderResult<i16> {
+    let code = br.read_cb(mv_cb)? as i16;
+    if code == 0 { return Ok(0) }
+    if !br.read_bool()? {
+        Ok(code)
+    } else {
+        Ok(-code)
+    }
+}
+
+fn decode_mv(br: &mut BitReader, mv_cb: &Codebook<u8>) -> DecoderResult<MV> {
+    let xval = decode_mv_component(br, mv_cb)?;
+    let yval = decode_mv_component(br, mv_cb)?;
+    Ok(MV::new(xval, yval))
+}
+
+impl<'a> BlockDecoder for Intel263BR<'a> {
+
+#[allow(unused_variables)]
+    fn decode_pichdr(&mut self) -> DecoderResult<PicInfo> {
+        let mut br = &mut self.br;
+        let syncw = br.read(22)?;
+        validate!(syncw == 0x000020);
+        let tr = br.read(8)? as u8;
+        check_marker(br)?;
+        let id = br.read(1)?;
+        validate!(id == 0);
+        br.read(1)?; // split screen indicator
+        br.read(1)?; // document camera indicator
+        br.read(1)?; // freeze picture release
+        let mut sfmt = br.read(3)?;
+        validate!((sfmt != 0b000) && (sfmt != 0b110));
+        let is_intra = !br.read_bool()?;
+        let umv = br.read_bool()?;
+        br.read(1)?; // syntax arithmetic coding
+        let apm = br.read_bool()?;
+        self.is_pb = br.read_bool()?;
+        if sfmt == 0b111 {
+            sfmt = br.read(3)?;
+            validate!((sfmt != 0b000) && (sfmt != 0b111));
+            br.read(2)?; // unknown flags
+            let deblock = br.read_bool()?;
+            br.read(1)?; // unknown flag
+            let pbplus = br.read_bool()?;
+            br.read(5)?; // unknown flags
+            let marker = br.read(5)?;
+            validate!(marker == 1);
+        }
+        let w; let h;
+        if sfmt == 0b110 {
+            let par = br.read(4)?;
+            w = ((br.read(9)? + 1) * 4) as usize;
+            check_marker(br)?;
+            h = ((br.read(9)? + 1) * 4) as usize;
+            if par == 0b1111 {
+                let pixw = br.read(8)?;
+                let pixh = br.read(8)?;
+                validate!((pixw != 0) && (pixh != 0));
+            }
+        } else {
+            let (w_, h_) = H263_SIZES[sfmt as usize];
+            w = w_;
+            h = h_;
+        }
+        let quant = br.read(5)?;
+        let cpm = br.read_bool()?;
+        validate!(!cpm);
+        if self.is_pb {
+            let trb = br.read(3)?;
+            let dbquant = br.read(2)?;
+        }
+        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());
+        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);
+        Ok(picinfo)
+    }
+
+    #[allow(unused_variables)]
+    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);
+        let ret = Slice::new(0, self.gob_no, gquant as u8);
+        self.gob_no += 1;
+        Ok(ret)
+    }
+
+    fn decode_block_header(&mut self, info: &PicInfo, slice: &Slice) -> DecoderResult<BlockInfo> {
+        let mut br = &mut self.br;
+        let mut q = slice.get_quant();
+        match info.get_mode() {
+            Type::I => {
+                    let mut cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?;
+                    while cbpc == 8 { cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?; }
+                    let cbpy = br.read_cb(&self.tables.cbpy_cb)?;
+                    let cbp = (cbpy << 2) | (cbpc & 3);
+                    let dquant = (cbpc & 4) != 0;
+                    if dquant {
+                        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)?; }
+                    let is_intra = (cbpc & 0x04) != 0;
+                    let dquant   = (cbpc & 0x08) != 0;
+                    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 cbpy = br.read_cb(&self.tables.cbpy_cb)?;
+                        let cbp = (cbpy << 2) | (cbpc & 3);
+                        if dquant {
+                            let idx = br.read(2)? as usize;
+                            q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8;
+                        }
+                        let mut binfo = BlockInfo::new(Type::I, cbp, q);
+                        if self.is_pb {
+                            for _ in 0..pb_mv_count {
+                                mvec.push(decode_mv(br, &self.tables.mv_cb)?);
+                            }
+                            binfo.set_mv2(cbpb, 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 mut cbpy = br.read_cb(&self.tables.cbpy_cb)?;
+//                    if /* !aiv && */(cbpc & 3) != 3 {
+                        cbpy ^= 0xF;
+//                    }
+                    let cbp = (cbpy << 2) | (cbpc & 3);
+                    if dquant {
+                        let idx = br.read(2)? as usize;
+                        q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8;
+                    }
+                    let mut binfo = BlockInfo::new(Type::P, cbp, q);
+                    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] = [
+                                decode_mv(br, &self.tables.mv_cb)?,
+                                decode_mv(br, &self.tables.mv_cb)?,
+                                decode_mv(br, &self.tables.mv_cb)?,
+                                decode_mv(br, &self.tables.mv_cb)?
+                            ];
+                        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 mv = decode_mv(br, &self.tables.mv_cb)?;
+                            mvec.push(mv);
+                        }
+                        binfo.set_mv2(cbpb, mvec.as_slice());
+                    }
+//println!("@{}",br.tell());
+                    Ok(binfo)
+                },
+            _ => { Err(DecoderError::InvalidData) },
+        }
+    }
+
+    #[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)
+    }
+
+    #[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)
+    }
+
+#[allow(unused_variables)]
+    fn calc_mv(&mut self, vec: MV) {}
+
+    fn is_slice_end(&mut self) -> bool { self.br.peek(16) == 0 }
+}
+
+impl Intel263Decoder {
+    fn new() -> Self {
+        let mut coderead = H263ShortCodeReader::new(H263_INTRA_MCBPC);
+        let intra_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
+        let mut coderead = H263ShortCodeReader::new(H263_INTER_MCBPC);
+        let inter_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
+        let mut coderead = H263ShortCodeReader::new(H263_CBPY);
+        let cbpy_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
+        let mut coderead = H263RLCodeReader::new(H263_RL_CODES);
+        let rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
+        let mut coderead = H263RLCodeReader::new(H263_RL_CODES_AIC);
+        let aic_rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
+        let mut coderead = H263ShortCodeReader::new(H263_MV);
+        let mv_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
+        let tables = Tables {
+            intra_mcbpc_cb: intra_mcbpc_cb,
+            inter_mcbpc_cb: inter_mcbpc_cb,
+            cbpy_cb:        cbpy_cb,
+            rl_cb:          rl_cb,
+            aic_rl_cb:      aic_rl_cb,
+            mv_cb:          mv_cb,
+        };
+
+        Intel263Decoder{
+            info:           Rc::new(DUMMY_CODEC_INFO),
+            dec:            DCT8x8VideoDecoder::new(),
+            tables:         tables,
+        }
+    }
+}
+
+impl NADecoder for Intel263Decoder {
+    fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            let w = vinfo.get_width();
+            let h = vinfo.get_height();
+            let fmt = formats::YUV420_FORMAT;
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt));
+            self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+
+        if src.len() == 8 {
+            let bret = self.dec.get_stored_pframe();
+            let buftype;
+            let is_skip;
+            if let Ok(btype) = bret {
+                buftype = btype;
+                is_skip = false;
+            } else {
+                buftype = NABufferType::None;
+                is_skip = true;
+            }
+            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 });
+            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)?;
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+        frm.set_keyframe(self.dec.is_intra());
+        frm.set_frame_type(if self.dec.is_intra() { FrameType::I } else { FrameType::P });
+        Ok(Rc::new(RefCell::new(frm)))
+    }
+}
+
+
+pub fn get_decoder() -> Box<NADecoder> {
+    Box::new(Intel263Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use codecs::*;
+    use demuxers::*;
+    use io::byteio::*;
+
+    #[test]
+    fn test_intel263() {
+        let avi_dmx = find_demuxer("avi").unwrap();
+        let mut file = File::open("assets/neal73_saber.avi").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let mut dmx = avi_dmx.new_demuxer(&mut br);
+        dmx.open().unwrap();
+
+        let mut decs: Vec<Option<Box<NADecoder>>> = Vec::new();
+        for i in 0..dmx.get_num_streams() {
+            let s = dmx.get_stream(i).unwrap();
+            let info = s.get_info();
+            let decfunc = find_decoder(info.get_name());
+            if let Some(df) = decfunc {
+                let mut dec = (df)();
+                dec.init(info).unwrap();
+                decs.push(Some(dec));
+            } else {
+                decs.push(None);
+            }
+        }
+
+        loop {
+            let pktres = dmx.get_frame();
+            if let Err(e) = pktres {
+                if e == DemuxerError::EOF { break; }
+                panic!("error");
+            }
+            let pkt = pktres.unwrap();
+            //if pkt.get_pts().unwrap() > 263 { break; }
+            let streamno = pkt.get_stream().get_id() as usize;
+            if let Some(ref mut dec) = decs[streamno] {
+                let frm = dec.decode(&pkt).unwrap();
+                if pkt.get_stream().get_info().is_video() {
+                    write_pgmyuv("ih263_", streamno, pkt.get_pts().unwrap(), frm);
+                }
+            }
+        }
+//panic!("THE END");
+    }
+}
index 625485e1ed4ed8382c2957b2bc2f4add44863390..ec67a4d7a9a38d78b3b2f91d8460528c4f161ee9 100644 (file)
@@ -17,7 +17,7 @@ pub enum DecoderError {
     Bug,
 }
 
-type DecoderResult<T> = Result<T, DecoderError>;
+pub type DecoderResult<T> = Result<T, DecoderError>;
 
 impl From<ByteIOError> for DecoderError {
     fn from(_: ByteIOError) -> Self { DecoderError::ShortData }
@@ -36,6 +36,15 @@ impl From<CodebookError> for DecoderError {
     fn from(_: CodebookError) -> Self { DecoderError::InvalidData }
 }
 
+macro_rules! validate {
+    ($a:expr) => { if !$a { return Err(DecoderError::InvalidData); } };
+}
+
+mod blockdsp;
+mod blockdec;
+mod h263code;
+mod h263data;
+
 #[allow(dead_code)]
 struct HAMShuffler {
     lastframe: Option<NAVideoBuffer<u8>>,
@@ -104,16 +113,14 @@ pub struct DecoderInfo {
     get_decoder: fn () -> Box<NADecoder>,
 }
 
-macro_rules! validate {
-    ($a:expr) => { if !$a { return Err(DecoderError::InvalidData); } };
-}
-
 #[cfg(feature="decoder_gdvvid")]
 mod gremlinvideo;
 #[cfg(feature="decoder_indeo2")]
 mod indeo2;
 #[cfg(feature="decoder_indeo3")]
 mod indeo3;
+
+mod intel263;
 #[cfg(feature="decoder_pcm")]
 mod pcm;
 
@@ -125,6 +132,8 @@ const DECODERS: &[DecoderInfo] = &[
 #[cfg(feature="decoder_indeo3")]
     DecoderInfo { name: "indeo3", get_decoder: indeo3::get_decoder },
 
+    DecoderInfo { name: "intel263", get_decoder: intel263::get_decoder },
+
 #[cfg(feature="decoder_pcm")]
     DecoderInfo { name: "pcm", get_decoder: pcm::get_decoder },
 ];
@@ -147,6 +156,7 @@ use std::io::prelude::*;
 #[allow(dead_code)]
 fn write_pgmyuv(pfx: &str, strno: usize, num: u64, frmref: NAFrameRef) {
     let frm = frmref.borrow();
+    if let NABufferType::None = frm.get_buffer() { return; }
     let name = format!("assets/{}out{:02}_{:04}.pgm", pfx, strno, num);
     let mut ofile = File::create(name).unwrap();
     let buf = frm.get_buffer().get_vbuf().unwrap();