X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-qt%2Fsrc%2Fcodecs%2Fqdmcommon.rs;fp=nihav-qt%2Fsrc%2Fcodecs%2Fqdmcommon.rs;h=601114091e47c39ca986aa7f8346760846d49d94;hb=4c1582cf2e275af7c0f4a2c1a397fed5b68d31d5;hp=0000000000000000000000000000000000000000;hpb=d341f57a0caf409d7dcc258b396cdee2080be399;p=nihav.git diff --git a/nihav-qt/src/codecs/qdmcommon.rs b/nihav-qt/src/codecs/qdmcommon.rs new file mode 100644 index 0000000..6011140 --- /dev/null +++ b/nihav-qt/src/codecs/qdmcommon.rs @@ -0,0 +1,199 @@ +use nihav_core::codecs::*; +use nihav_core::io::bitreader::*; +use nihav_core::io::codebook::*; + +/// Bitstream reader. +#[derive(Debug,Clone)] +pub struct QdmBitReader<'a> { + cache: u32, + bits: u8, + pos: usize, + src: &'a [u8], +} + +#[allow(clippy::identity_op)] +#[allow(dead_code)] +impl<'a> QdmBitReader<'a> { + pub fn new(src: &'a [u8]) -> Self { + Self{ cache: 0, pos: 0, bits: 0, src } + } + pub fn tell(&self) -> usize { + self.pos * 8 - (self.bits as usize) + } + pub fn left(&self) -> isize { + ((self.src.len() as isize) - (self.pos as isize)) * 8 + (self.bits as isize) + } + fn refill(&mut self) { + while self.bits <= 24 { + let byte = if self.pos < self.src.len() { + self.pos += 1; + self.src[self.pos - 1] + } else { + self.pos += 1; + 0 + }; + self.cache |= u32::from(byte) << self.bits; + self.bits += 8; + } + } + fn read_cache(&mut self, nbits: u8) -> u32 { + ((1 << nbits) - 1) & self.cache + } + fn skip_cache(&mut self, nbits: u8) { + self.cache >>= nbits; + self.bits -= nbits; + } + fn reset_cache(&mut self) { + self.bits = 0; + self.cache = 0; + } + pub fn read(&mut self, nbits: u8) -> u32 { + if nbits == 0 { return 0; } + if nbits > 32 { return 0; } + if self.bits < nbits { + self.refill(); + } + let res = self.read_cache(nbits); + self.skip_cache(nbits); + res + } + pub fn read_bool(&mut self) -> bool { + if self.bits < 1 { + self.refill(); + } + let res = self.read_cache(1); + self.skip_cache(1); + res == 1 + } + pub fn peek(&mut self, nbits: u8) -> u32 { + if nbits > 32 { return 0 } + if self.bits < nbits { self.refill(); } + self.read_cache(nbits) + } + pub fn skip(&mut self, nbits: u32) { + if u32::from(self.bits) >= nbits { + self.skip_cache(nbits as u8); + return; + } + let mut skip_bits = nbits - u32::from(self.bits); + self.reset_cache(); + self.pos += ((skip_bits / 32) * 4) as usize; + skip_bits &= 0x1F; + self.refill(); + if skip_bits > 0 { + self.skip_cache(skip_bits as u8); + } + } +} + +impl<'a, S: Copy> CodebookReader for QdmBitReader<'a> { + #[allow(unused_variables)] + fn read_cb(&mut self, cb: &Codebook) -> CodebookResult { + let mut esc = true; + let mut idx = 0; + let mut lut_bits = cb.lut_bits; + while esc { + let lut_idx = (self.peek(lut_bits) as usize) + (idx as usize); + if cb.table[lut_idx] == TABLE_FILL_VALUE { return Err(CodebookError::InvalidCode); } + let bits = cb.table[lut_idx] & 0x7F; + esc = (cb.table[lut_idx] & 0x80) != 0; + idx = (cb.table[lut_idx] >> 8) as usize; + let skip_bits = if esc { u32::from(lut_bits) } else { bits }; + self.skip(skip_bits as u32); + lut_bits = bits as u8; + } + Ok(cb.syms[idx]) + } +} + + +pub fn to_signed(val: i32) -> i32 { + if (val & 1) != 0 { + (val + 1) >> 1 + } else { + -(val >> 1) + } +} + +pub trait QdmcCodeReader { + fn read_code(&mut self, cb: &Codebook) -> DecoderResult; + fn read_code_long(&mut self, cb: &Codebook) -> DecoderResult; +} + +impl<'a> QdmcCodeReader for BitReader<'a> { + fn read_code(&mut self, cb: &Codebook) -> DecoderResult { + let idx = self.read_cb(cb)?; + if idx > 0 { + Ok(u32::from(idx - 1)) + } else { + let len = (self.read(3)? as u8) + 1; + let val = self.read(len)?; + Ok(val) + } + } + fn read_code_long(&mut self, cb: &Codebook) -> DecoderResult { + let idx = self.read_code(cb)? as usize; + validate!(idx < ESCAPE_PREFIX.len()); + let add = self.read((idx >> 2) as u8)?; + Ok(ESCAPE_PREFIX[idx] + add) + } +} + +impl<'a> QdmcCodeReader for QdmBitReader<'a> { + fn read_code(&mut self, cb: &Codebook) -> DecoderResult { + let idx = self.read_cb(cb)?; + if idx > 0 { + Ok(u32::from(idx - 1)) + } else { + let len = (self.read(3) as u8) + 1; + let val = self.read(len); + Ok(val) + } + } + fn read_code_long(&mut self, cb: &Codebook) -> DecoderResult { + let idx = self.read_code(cb)? as usize; + validate!(idx < ESCAPE_PREFIX.len()); + let add = self.read((idx >> 2) as u8); + Ok(ESCAPE_PREFIX[idx] + add) + } +} + +const ESCAPE_PREFIX: [u32; 65] = [ + 0x00000, 0x00001, 0x00002, 0x00003, 0x00004, 0x00006, 0x00008, 0x0000A, + 0x0000C, 0x00010, 0x00014, 0x00018, 0x0001C, 0x00024, 0x0002C, 0x00034, + 0x0003C, 0x0004C, 0x0005C, 0x0006C, 0x0007C, 0x0009C, 0x000BC, 0x000DC, + 0x000FC, 0x0013C, 0x0017C, 0x001BC, 0x001FC, 0x0027C, 0x002FC, 0x0037C, + 0x003FC, 0x004FC, 0x005FC, 0x006FC, 0x007FC, 0x009FC, 0x00BFC, 0x00DFC, + 0x00FFC, 0x013FC, 0x017FC, 0x01BFC, 0x01FFC, 0x027FC, 0x02FFC, 0x037FC, + 0x03FFC, 0x04FFC, 0x05FFC, 0x06FFC, 0x07FFC, 0x09FFC, 0x0BFFC, 0x0DFFC, + 0x0FFFC, 0x13FFC, 0x17FFC, 0x1BFFC, 0x1FFFC, 0x27FFC, 0x2FFFC, 0x37FFC, + 0x3FFFC +]; + +pub struct RNG { + pub seed: u32, +} + +impl RNG { + pub fn new() -> Self { Self { seed: 0 } } + pub fn next(&mut self) -> u32 { + self.seed = self.seed.wrapping_mul(0x343FD).wrapping_add(0x269EC3); + self.seed + } + pub fn next_float(&mut self) -> f32 { + self.next(); + ((((self.seed >> 16) & 0x7FFF) as f32) - 16384.0) / 16384.0 + } +} + +#[derive(Clone,Copy)] +pub struct Tone { + pub ch: u8, + pub phase: u8, + pub offset: u8, + pub freq: u16, + pub amp_idx: u8, +} + +pub const MAX_TONES: usize = 8192; +