add nihav_qt crate with some QuickTime codecs
[nihav.git] / nihav-qt / src / codecs / svq1.rs
diff --git a/nihav-qt/src/codecs/svq1.rs b/nihav-qt/src/codecs/svq1.rs
new file mode 100644 (file)
index 0000000..68db3a3
--- /dev/null
@@ -0,0 +1,565 @@
+use nihav_core::codecs::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+use nihav_core::io::intcode::*;
+use nihav_codec_support::codecs::{MV, ZERO_MV};
+use nihav_codec_support::codecs::blockdsp::*;
+
+use super::svq1data::*;
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+enum SVQ1FrameType {
+    I,
+    P,
+    Drop,
+}
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+enum BlockType {
+    Intra,
+    Skip,
+    OneMV,
+    FourMV,
+}
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+#[allow(clippy::enum_variant_names)]
+enum BlockDiv {
+    Div16x16,
+    Div16x8,
+    Div8x8,
+    Div8x4,
+    Div4x4,
+    Div4x2,
+}
+
+impl BlockDiv {
+    fn is_final(self) -> bool { self == BlockDiv::Div4x2 }
+    fn split(self) -> (Self, usize, usize) {
+        match self {
+            BlockDiv::Div16x16 => (BlockDiv::Div16x8, 0, 8),
+            BlockDiv::Div16x8  => (BlockDiv::Div8x8, 8, 0),
+            BlockDiv::Div8x8   => (BlockDiv::Div8x4, 0, 4),
+            BlockDiv::Div8x4   => (BlockDiv::Div4x4, 4, 0),
+            BlockDiv::Div4x4   => (BlockDiv::Div4x2, 0, 2),
+            BlockDiv::Div4x2   => unreachable!(),
+        }
+    }
+    fn get_size(self) -> (usize, usize) {
+        match self {
+            BlockDiv::Div16x16 => (16, 16),
+            BlockDiv::Div16x8  => (16,  8),
+            BlockDiv::Div8x8   => ( 8,  8),
+            BlockDiv::Div8x4   => ( 8,  4),
+            BlockDiv::Div4x4   => ( 4,  4),
+            BlockDiv::Div4x2   => ( 4,  2),
+        }
+    }
+    fn get_level(self) -> usize {
+        match self {
+            BlockDiv::Div16x16 => 5,
+            BlockDiv::Div16x8  => 4,
+            BlockDiv::Div8x8   => 3,
+            BlockDiv::Div8x4   => 2,
+            BlockDiv::Div4x4   => 1,
+            BlockDiv::Div4x2   => 0,
+        }
+    }
+}
+
+const BLOCK_TYPES: [BlockType; 4] = [ BlockType::Skip, BlockType::OneMV, BlockType::FourMV, BlockType::Intra ];
+
+impl SVQ1FrameType {
+    fn is_ref(self) -> bool {
+        self != SVQ1FrameType::Drop
+    }
+    fn is_intra(self) -> bool {
+        self == SVQ1FrameType::I
+    }
+    fn to_frame_type(self) -> FrameType {
+        match self {
+            SVQ1FrameType::I => FrameType::I,
+            SVQ1FrameType::P => FrameType::P,
+            SVQ1FrameType::Drop => FrameType::P,
+        }
+    }
+    fn from_id(id: u32) -> DecoderResult<Self> {
+        match id {
+            0 => Ok(SVQ1FrameType::I),
+            1 => Ok(SVQ1FrameType::P),
+            2 => Ok(SVQ1FrameType::Drop),
+            _ => Err(DecoderError::InvalidData),
+        }
+    }
+}
+
+struct SVQ1DescReader {
+    table:  &'static [[u8; 2]],
+    bias:   i16,
+}
+
+impl CodebookDescReader<i16> for SVQ1DescReader {
+    fn bits(&mut self, idx: usize) -> u8 { self.table[idx][1] }
+    fn code(&mut self, idx: usize) -> u32 { u32::from(self.table[idx][0]) }
+    fn sym(&mut self, idx: usize) -> i16 { (idx as i16) + self.bias }
+    fn len(&mut self) -> usize { self.table.len() }
+}
+
+struct SVQ1InterMeanDescReader {}
+
+impl CodebookDescReader<i16> for SVQ1InterMeanDescReader {
+    fn bits(&mut self, idx: usize) -> u8 { SVQ_INTER_MEAN_CODES[idx][1] as u8 }
+    fn code(&mut self, idx: usize) -> u32 { u32::from(SVQ_INTER_MEAN_CODES[idx][0]) }
+    fn sym(&mut self, idx: usize) -> i16 { (idx as i16) - 256 }
+    fn len(&mut self) -> usize { SVQ_INTER_MEAN_CODES.len() }
+}
+
+struct SVQ1Decoder {
+    info:       NACodecInfoRef,
+    width:      usize,
+    height:     usize,
+    ref_frm:    Option<NAVideoBufferRef<u8>>,
+    mvs:        Vec<MV>,
+    intra_stages_cb:    Vec<Codebook<i16>>,
+    inter_stages_cb:    Vec<Codebook<i16>>,
+    intra_mean_cb:      Codebook<i16>,
+    inter_mean_cb:      Codebook<i16>,
+    mv_cb:              Codebook<i16>,
+
+    div_list:           [(BlockDiv, usize); 64],
+}
+
+impl SVQ1Decoder {
+    #[allow(clippy::needless_range_loop)]
+    fn new() -> Self {
+        let mut intra_stages_cb = Vec::with_capacity(6);
+        for i in 0..6 {
+            let mut cbd = SVQ1DescReader { table: &SVQ_INTRA_STAGE_CODES[i], bias: -1 };
+            let cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+            intra_stages_cb.push(cb);
+        }
+        let mut inter_stages_cb = Vec::with_capacity(6);
+        for i in 0..6 {
+            let mut cbd = SVQ1DescReader { table: &SVQ_INTER_STAGE_CODES[i], bias: -1 };
+            let cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+            inter_stages_cb.push(cb);
+        }
+        let mut cbd = SVQ1DescReader { table: &SVQ_INTRA_MEAN_CODES, bias: 0 };
+        let intra_mean_cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+        let mut cbd = SVQ1InterMeanDescReader {};
+        let inter_mean_cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+        let mut cbd = SVQ1DescReader { table: &SVQ_MV_CODES, bias: 0 };
+        let mv_cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+        Self {
+            info:       NACodecInfoRef::default(),
+            width:      0,
+            height:     0,
+            ref_frm:    None,
+            mvs:        Vec::new(),
+            intra_stages_cb, inter_stages_cb, intra_mean_cb, inter_mean_cb, mv_cb,
+            div_list:   [(BlockDiv::Div16x16, 0); 64],
+        }
+    }
+    fn read_mv(&self, br: &mut BitReader) -> DecoderResult<MV> {
+        let mut x                       = br.read_cb(&self.mv_cb)?;
+        if x > 0 && br.read_bool()? {
+            x = -x;
+        }
+        let mut y                       = br.read_cb(&self.mv_cb)?;
+        if y > 0 && br.read_bool()? {
+            y = -y;
+        }
+        Ok(MV { x, y })
+    }
+    #[allow(clippy::too_many_arguments)]
+    fn pred_mv(&self, x: usize, y: usize, w: usize, mv_idx: usize, mvstride: usize, blk_idx: usize, diff: MV) -> MV {
+        let a_mv = if x > 0 || (blk_idx & 1) != 0 { self.mvs[mv_idx - 1] } else { ZERO_MV };
+        let b_mv = if y > 0 || (blk_idx & 2) != 0 { self.mvs[mv_idx - mvstride]  } else { a_mv };
+        let c_mv = match blk_idx {
+                0 => if y > 0 && x + 16 < w { self.mvs[mv_idx + 2 - mvstride] } else { ZERO_MV },
+                1 => if y > 0 && x + 16 < w { self.mvs[mv_idx + 1 - mvstride] } else { ZERO_MV },
+                2 => self.mvs[mv_idx + 1 - mvstride],
+                _ => self.mvs[mv_idx - 1 - mvstride],
+            };
+        let mut new_mv = diff + MV::pred(a_mv, b_mv, c_mv);
+        if      new_mv.x >=  32 { new_mv.x -= 64; }
+        else if new_mv.x <= -32 { new_mv.x += 64; }
+        if      new_mv.y >=  32 { new_mv.y -= 64; }
+        else if new_mv.y <= -32 { new_mv.y += 64; }
+        new_mv
+    }
+    fn decode_intra_block(&mut self, br: &mut BitReader, dst: &mut [u8], dstride: usize) -> DecoderResult<()> {
+        self.div_list[0] = (BlockDiv::Div16x16, 0);
+        let mut idx = 0;
+        let mut end = 1;
+        while idx < end {
+            let (div, off) = self.div_list[idx];
+            if !div.is_final() && br.read_bool()? {
+                let (ndiv, xoff, yoff) = div.split();
+                self.div_list[end] = (ndiv, off);
+                end += 1;
+                self.div_list[end] = (ndiv, off + xoff + yoff * dstride);
+                end += 1;
+            } else {
+                let level = div.get_level();
+                let stages              = br.read_cb(&self.intra_stages_cb[level])?;
+                if level > 3 {
+                    validate!(stages <= 0);
+                }
+                let (w, h) = div.get_size();
+                let fill = if stages < 0 { 0 } else { br.read_cb(&self.intra_mean_cb)? } as u8;
+                for line in dst[off..].chunks_mut(dstride).take(h) {
+                    for el in line.iter_mut().take(w) {
+                        *el = fill;
+                    }
+                }
+                if stages > 0 {
+                    for stage in 0..(stages as usize) {
+                        let idx         = br.read(4)? as usize;
+                        let src: &[i8] = match div {
+                                BlockDiv::Div8x8 => &SVQ_INTRA_CB_8X8[stage * 16 + idx],
+                                BlockDiv::Div8x4 => &SVQ_INTRA_CB_8X4[stage * 16 + idx],
+                                BlockDiv::Div4x4 => &SVQ_INTRA_CB_4X4[stage * 16 + idx],
+                                BlockDiv::Div4x2 => &SVQ_INTRA_CB_4X2[stage * 16 + idx],
+                                _ => unreachable!(),
+                            };
+                        for (line, src) in dst[off..].chunks_mut(dstride).zip(src.chunks(w)) {
+                            for x in 0..w {
+                                line[x] = (i16::from(line[x]) + i16::from(src[x])).max(0).min(255) as u8;
+                            }
+                        }
+                    }
+                }
+            }
+            idx += 1;
+        }
+        Ok(())
+    }
+    fn decode_inter_block(&mut self, br: &mut BitReader, dst: &mut [u8], dstride: usize) -> DecoderResult<()> {
+        self.div_list[0] = (BlockDiv::Div16x16, 0);
+        let mut idx = 0;
+        let mut end = 1;
+        while idx < end {
+            let (div, off) = self.div_list[idx];
+            if !div.is_final() && br.read_bool()? {
+                let (ndiv, xoff, yoff) = div.split();
+                self.div_list[end] = (ndiv, off);
+                end += 1;
+                self.div_list[end] = (ndiv, off + xoff + yoff * dstride);
+                end += 1;
+            } else {
+                let level = div.get_level();
+                let stages              = br.read_cb(&self.inter_stages_cb[level])?;
+                if level > 3 {
+                    validate!(stages <= 0);
+                }
+                let (w, h) = div.get_size();
+                let fill = if stages < 0 { 0 } else { br.read_cb(&self.inter_mean_cb)? };
+                if fill != 0 {
+                    for line in dst[off..].chunks_mut(dstride).take(h) {
+                        for el in line.iter_mut().take(w) {
+                            *el = (i16::from(*el) + fill).max(0).min(255) as u8;
+                        }
+                    }
+                }
+                if stages > 0 {
+                    for stage in 0..(stages as usize) {
+                        let idx         = br.read(4)? as usize;
+                        let src: &[i8] = match div {
+                                BlockDiv::Div8x8 => &SVQ_INTER_CB_8X8[stage * 16 + idx],
+                                BlockDiv::Div8x4 => &SVQ_INTER_CB_8X4[stage * 16 + idx],
+                                BlockDiv::Div4x4 => &SVQ_INTER_CB_4X4[stage * 16 + idx],
+                                BlockDiv::Div4x2 => &SVQ_INTER_CB_4X2[stage * 16 + idx],
+                                _ => unreachable!(),
+                            };
+                        for (line, src) in dst[off..].chunks_mut(dstride).zip(src.chunks(w)) {
+                            for x in 0..w {
+                                line[x] = (i16::from(line[x]) + i16::from(src[x])).max(0).min(255) as u8;
+                            }
+                        }
+                    }
+                }
+            }
+            idx += 1;
+        }
+        Ok(())
+    }
+    fn decode_plane(&mut self, br: &mut BitReader, dframe: &mut NASimpleVideoFrame<u8>, plane: usize, is_intra: bool) -> DecoderResult<()> {
+        let (w, h) = if plane == 0 {
+                ((self.width + 15) & !15, (self.height + 15) & !15)
+            } else {
+                ((self.width / 4 + 15) & !15, (self.height / 4 + 15) & !15)                
+            };
+        let mvstride = w / 8;
+        self.mvs.truncate(0);
+        self.mvs.resize(mvstride * (h / 8), ZERO_MV);
+        let mut mv_idx = 0;
+
+        let mut doff = dframe.offset[plane];
+        let dstride = dframe.stride[plane];
+        for y in (0..h).step_by(16) {
+            for x in (0..w).step_by(16) {
+                let block_type = if is_intra {
+                        BlockType::Intra
+                    } else {
+                        let idx         = br.read_code(UintCodeType::LimitedZeroes(3))? as usize;
+                        BLOCK_TYPES[idx]
+                    };
+                match block_type {
+                    BlockType::Intra => {
+                        self.decode_intra_block(br, &mut dframe.data[doff + x..], dstride)?;
+                    },
+                    BlockType::Skip => {
+                        if let Some(ref rfrm) = self.ref_frm {
+                            let sstride = rfrm.get_stride(plane);
+                            let soff = rfrm.get_offset(plane) + y * sstride;
+                            let src = &rfrm.get_data()[soff + x..];
+                            let dst = &mut dframe.data[doff + x..];
+                            for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(16) {
+                                dline[..16].copy_from_slice(&sline[..16]);
+                            }
+                        }
+                    },
+                    BlockType::OneMV => {
+                        let mv = self.read_mv(br)?;
+                        let new_mv = self.pred_mv(x, y, w, mv_idx + x / 8, mvstride, 0, mv);
+                        self.mvs[mv_idx + x / 8] = new_mv;
+                        self.mvs[mv_idx + x / 8 + 1] = new_mv;
+                        self.mvs[mv_idx + mvstride + x / 8] = new_mv;
+                        self.mvs[mv_idx + mvstride + x / 8 + 1] = new_mv;
+                        if let Some(ref rfrm) = self.ref_frm {
+                            let mode = ((new_mv.x & 1) + (new_mv.y & 1) * 2) as usize;
+                            copy_block(dframe, rfrm.clone(), plane, x, y, new_mv.x >> 1, new_mv.y >> 1, 16, 16, 0, 1, mode, HALFPEL_INTERP_FUNCS);
+                        }
+                        self.decode_inter_block(br, &mut dframe.data[doff + x..], dstride)?;
+                    },
+                    BlockType::FourMV => {
+                        for i in 0..4 {
+                            let mv = self.read_mv(br)?;
+                            let cur_idx = mv_idx + x / 8 + (i & 1) + (i >> 1) * mvstride;
+                            let new_mv = self.pred_mv(x, y, w, cur_idx, mvstride, i, mv);
+                            self.mvs[cur_idx] = new_mv;
+                            if let Some(ref rfrm) = self.ref_frm {
+                                let mode = ((new_mv.x & 1) + (new_mv.y & 1) * 2) as usize;
+                                copy_block(dframe, rfrm.clone(), plane, x + (i & 1) * 8, y + (i >> 1) * 8, new_mv.x >> 1, new_mv.y >> 1, 8, 8, 0, 1, mode, HALFPEL_INTERP_FUNCS);
+                            }
+                        }
+                        self.decode_inter_block(br, &mut dframe.data[doff + x..], dstride)?;
+                    },
+                };
+            }
+            doff += dstride * 16;
+            mv_idx += mvstride * 2;
+        }
+        Ok(())
+    }
+}
+
+impl NADecoder for SVQ1Decoder {
+    fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            self.width  = vinfo.get_width();
+            self.height = vinfo.get_height();
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, YUV410_FORMAT));
+            self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+            supp.pool_u8.set_dec_bufs(2);
+            supp.pool_u8.prealloc_video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV410_FORMAT), 6)?;
+            self.mvs = Vec::with_capacity((self.width + 15) / 4 * ((self.height + 15) / 4));
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    #[allow(clippy::collapsible_if)]
+    fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        validate!(src.len() >= 2);
+        let mut br = BitReader::new(&src, BitReaderMode::BE);
+
+        let fcode                       = br.read(22)?;
+        validate!((fcode & 0x60) != 0);
+        let _pts                        = br.read(8)?;
+        let ptype                       = br.read(2)?;
+        let ftype = SVQ1FrameType::from_id(ptype)?;
+        let mut frm_data = Vec::new();
+        if fcode != 0x20 {
+            frm_data.extend_from_slice(&src);
+            for i in 0..4 {
+                let a = frm_data[i * 4 + 4];
+                let b = frm_data[i * 4 + 5];
+                let c = frm_data[i * 4 + 6];
+                let d = frm_data[i * 4 + 7];
+                frm_data[i * 4 + 4] = c ^ frm_data[32 - i * 4];
+                frm_data[i * 4 + 5] = d ^ frm_data[33 - i * 4];
+                frm_data[i * 4 + 6] = a ^ frm_data[34 - i * 4];
+                frm_data[i * 4 + 7] = b ^ frm_data[35 - i * 4];
+            }
+            br = BitReader::new(&frm_data, BitReaderMode::BE);
+            br.skip(32)?;
+        }
+        if ftype.is_intra() {
+            if fcode == 0x50 || fcode == 0x60 {
+                let _checksum           = br.read(16)? as u16;
+//                let crc = calc_crc(frm_data.as_slice(), 0);
+//                validate!(crc == _checksum);
+            }
+            if fcode == 0x40 || fcode == 0x60 || fcode == 0x70 {
+                let str_len             = br.read(8)? as usize;
+                for _ in 0..str_len {
+                                          br.skip(8)?;
+                }
+            }
+                                          br.skip(2)?;
+                                          br.skip(2)?;
+                                          br.skip(1)?;
+            let size_id                 = br.read(3)? as usize;
+            let (w, h) = if size_id < FRAME_SIZES.len() {
+                    FRAME_SIZES[size_id]
+                } else {
+                    let w               = br.read(12)? as usize;
+                    let h               = br.read(12)? as usize;
+                    validate!(w >= 16 && h >= 16);
+                    (w, h)
+                };
+            if self.width != w || self.height != h {
+                self.flush();
+                self.width  = w;
+                self.height = h;
+                let vinfo = NAVideoInfo::new(self.width, self.height, false, YUV410_FORMAT);
+                supp.pool_u8.reset();
+                supp.pool_u8.prealloc_video(vinfo, 6)?;
+                let nmb = ((w + 15) / 4) * ((h + 15) / 4);
+                if self.mvs.capacity() < nmb {
+                    let add = nmb - self.mvs.capacity();
+                    self.mvs.reserve(add);
+                }
+            }
+        } else {
+            if self.ref_frm.is_none() {
+                return Err(DecoderError::MissingReference);
+            }
+        }
+        if br.read_bool()? {
+            let _pkt_crc                = br.read_bool()?;
+            let _comp_crc               = br.read_bool()?;
+            let marker                  = br.read(2)?;
+            validate!(marker == 0);
+        }
+        if br.read_bool()? {
+                                          br.skip(1)?;
+                                          br.skip(4)?;
+                                          br.skip(1)?;
+                                          br.skip(2)?;
+            while br.read_bool()? { }
+        }
+
+        let ret = supp.pool_u8.get_free();
+        if ret.is_none() {
+            return Err(DecoderError::AllocError);
+        }
+
+        let mut buf = ret.unwrap();
+        let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+        self.decode_plane(&mut br, &mut dframe, 0, ftype.is_intra())?;
+        self.decode_plane(&mut br, &mut dframe, 1, ftype.is_intra())?;
+        self.decode_plane(&mut br, &mut dframe, 2, ftype.is_intra())?;
+
+        if ftype.is_ref() {
+            self.ref_frm = Some(buf.clone());
+        }
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
+        frm.set_keyframe(ftype.is_intra());
+        frm.set_frame_type(ftype.to_frame_type());
+        Ok(frm.into_ref())
+    }
+    fn flush(&mut self) {
+        self.ref_frm = None;
+    }
+}
+
+impl NAOptionHandler for SVQ1Decoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+    Box::new(SVQ1Decoder::new())
+}
+
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_svq1() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "sorenson-video", "assets/QT/adpcm-bug.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x90c5eb74, 0xcb942d7d, 0x84c5e444, 0x7f1ba2c2],
+                            [0x650ae6f7, 0x9a0a6ec2, 0x0d907064, 0xb4c37321],
+                            [0xa04e865b, 0xdbd65920, 0x4703d7dd, 0x962707a1],
+                            [0xe89c98bc, 0x356791bb, 0xfb6f7302, 0x2250ef05],
+                            [0x282ef2a7, 0x235541b4, 0x55055d99, 0x1a8d0b29],
+                            [0x56328694, 0x27157f78, 0x4bc6ddda, 0x03dcde68],
+                            [0x5a694576, 0xd2434aea, 0x6859d48c, 0x275e02c9]]));
+    }
+}
+
+const FRAME_SIZES: [(usize, usize); 7] = [
+    (160, 120), (128,  96), (176, 144), (352, 288),
+    (704, 576), (240, 180), (320, 240)
+];
+
+/*const CRC_TABLE: [u16; 256] = [ //CCITT 16-bit CRC?
+    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+    0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+    0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+    0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+    0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+    0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+    0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+    0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+    0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+    0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+    0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+    0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+    0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+    0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+    0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+    0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+    0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+    0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+    0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+    0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+    0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+    0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+    0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+    0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+    0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+    0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+    0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+    0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+    0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+    0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+    0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+    0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+];
+
+fn calc_crc(src: &[u8], start: u16) -> u16 {
+    let mut crc = start;
+    for byte in src.iter() {
+        crc = CRC_TABLE[(*byte ^ ((crc >> 8) as u8)) as usize] ^ (crc << 8);
+    }
+    crc
+}*/