diff options
author | Kostya Shishkov <kostya.shishkov@gmail.com> | 2023-09-30 11:40:32 +0200 |
---|---|---|
committer | Kostya Shishkov <kostya.shishkov@gmail.com> | 2023-10-07 18:47:32 +0200 |
commit | 217de10bc01258d3a479c2784d6c5542c30b0f63 (patch) | |
tree | 1065933165fdab9be228abb02ffd35b79c4ff6f2 /nihav-rad/src/codecs/binkvidenc/bundle.rs | |
parent | 94cebb38b3bf2252d0863d517838718787bb4529 (diff) | |
download | nihav-217de10bc01258d3a479c2784d6c5542c30b0f63.tar.gz |
Bink Video encoder (only 'b' version for now)
Diffstat (limited to 'nihav-rad/src/codecs/binkvidenc/bundle.rs')
-rw-r--r-- | nihav-rad/src/codecs/binkvidenc/bundle.rs | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/nihav-rad/src/codecs/binkvidenc/bundle.rs b/nihav-rad/src/codecs/binkvidenc/bundle.rs new file mode 100644 index 0000000..5853169 --- /dev/null +++ b/nihav-rad/src/codecs/binkvidenc/bundle.rs @@ -0,0 +1,233 @@ +use std::collections::VecDeque; +use nihav_core::io::bitwriter::*; + +const BUNDLE_LEN_BITS: u8 = 13; +const MAX_BUNDLE_LEN: usize = 1 << BUNDLE_LEN_BITS; + +#[derive(Default)] +struct Bundle<T:Copy> { + bits: u8, + data: VecDeque<(usize, Vec<T>)>, + row: usize, + tmp: Vec<T>, + end: bool, + last_w: usize, +} + +impl<T:Copy> Bundle<T> { + fn reset(&mut self, bits: u8) { + self.bits = bits; + self.end = false; + self.last_w = 0; + } + fn new_row(&mut self, row: usize) { + self.row = row; + } + fn push(&mut self, val: T) { + self.tmp.push(val); + } + fn push_all(&mut self, slc: &[T]) { + self.tmp.extend_from_slice(slc); + } + fn end_row(&mut self) { + if !self.tmp.is_empty() { + let mut tmp = Vec::new(); + std::mem::swap(&mut tmp, &mut self.tmp); + self.data.push_back((self.row, tmp)); + } + } +} + +trait IntoU32 { + fn into_u32(self) -> u32; +} + +impl IntoU32 for u8 { + fn into_u32(self) -> u32 { u32::from(self) } +} + +impl IntoU32 for i8 { + fn into_u32(self) -> u32 { (self + 16) as u32 } +} + +impl IntoU32 for u16 { + fn into_u32(self) -> u32 { u32::from(self) } +} + +impl IntoU32 for i16 { + fn into_u32(self) -> u32 { (self + 1024) as u32 } +} + +impl Bundle<(u16, u8)> { + fn write(&mut self, bw: &mut BitWriter, cur_row: usize) { + if !self.data.is_empty() && self.data[0].0 == cur_row { + let (_, row_data) = self.data.pop_front().unwrap(); + for &(bits, len) in row_data.iter() { + bw.write(u32::from(bits), len); + } + } + } +} + +impl<T: Copy+IntoU32> Bundle<T> { + fn write(&mut self, bw: &mut BitWriter, cur_row: usize) { + if !self.end && cur_row == self.last_w { + let mut num_out = 0; + let mut len_out = 0; + for (_, row) in self.data.iter() { + if len_out + row.len() < MAX_BUNDLE_LEN { + len_out += row.len(); + num_out += 1; + } else { + break; + } + } + + bw.write(len_out as u32, BUNDLE_LEN_BITS); + if len_out == 0 { + self.end = true; + return; + } + for _ in 0..num_out { + let (row_no, row_data) = self.data.pop_front().unwrap(); + self.last_w = row_no + 1; + for &el in row_data.iter() { + bw.write(el.into_u32(), self.bits); + } + } + } + } +} + +#[derive(Default)] +pub struct Bundles { + btype: Bundle<u8>, + colors: Bundle<u8>, + pattern: Bundle<u8>, + xoff: Bundle<i8>, + yoff: Bundle<i8>, + intradc: Bundle<u16>, + interdc: Bundle<i16>, + intraq: Bundle<u8>, + interq: Bundle<u8>, + nresidues: Bundle<u8>, + other: Bundle<(u16, u8)>, +} + +macro_rules! whole_bundle { + ($self:expr, $func:ident) => { + $self.btype.$func(); + $self.colors.$func(); + $self.pattern.$func(); + $self.xoff.$func(); + $self.yoff.$func(); + $self.intradc.$func(); + $self.interdc.$func(); + $self.intraq.$func(); + $self.interq.$func(); + $self.nresidues.$func(); + $self.other.$func(); + }; + ($self:expr, $func:ident, $($args:expr),*) => { + $self.btype.$func($($args),*); + $self.colors.$func($($args),*); + $self.pattern.$func($($args),*); + $self.xoff.$func($($args),*); + $self.yoff.$func($($args),*); + $self.intradc.$func($($args),*); + $self.interdc.$func($($args),*); + $self.intraq.$func($($args),*); + $self.interq.$func($($args),*); + $self.nresidues.$func($($args),*); + $self.other.$func($($args),*); + } +} + +impl Bundles { + pub fn reset(&mut self) { + self.btype.reset(4); + self.colors.reset(8); + self.pattern.reset(8); + self.xoff.reset(5); + self.yoff.reset(5); + self.intradc.reset(11); + self.interdc.reset(11); + self.intraq.reset(4); + self.interq.reset(4); + self.nresidues.reset(7); + } + pub fn add_block_type(&mut self, btype: u8) { + self.btype.push(btype); + } + pub fn write(&mut self, bw: &mut BitWriter, row: usize) { + whole_bundle!(self, write, bw, row); + } + pub fn new_row(&mut self, row: usize) { + whole_bundle!(self, new_row, row); + } + pub fn end_row(&mut self) { + whole_bundle!(self, end_row); + } + + pub fn can_fit_raw_block(&self) -> bool { + self.colors.data.len() < MAX_BUNDLE_LEN - 1 - 64 + } + pub fn add_tokens(&mut self, tokens: &BlockTokens) { + self.colors.push_all(&tokens.colors); + self.pattern.push_all(&tokens.pattern); + self.xoff.push_all(&tokens.xoff); + self.yoff.push_all(&tokens.yoff); + self.intradc.push_all(&tokens.intradc); + self.interdc.push_all(&tokens.interdc); + self.intraq.push_all(&tokens.intraq); + self.interq.push_all(&tokens.interq); + self.nresidues.push_all(&tokens.nresidues); + self.other.push_all(&tokens.other); + } +} + +#[derive(Default)] +pub struct BlockTokens { + pub colors: Vec<u8>, + pub pattern: Vec<u8>, + pub xoff: Vec<i8>, + pub yoff: Vec<i8>, + pub intradc: Vec<u16>, + pub interdc: Vec<i16>, + pub intraq: Vec<u8>, + pub interq: Vec<u8>, + pub nresidues: Vec<u8>, + pub other: Vec<(u16, u8)>, +} + +impl BlockTokens { + pub fn new() -> Self { Self::default() } + pub fn clear(&mut self) { + self.colors.clear(); + self.pattern.clear(); + self.xoff.clear(); + self.yoff.clear(); + self.intradc.clear(); + self.interdc.clear(); + self.intraq.clear(); + self.interq.clear(); + self.nresidues.clear(); + self.other.clear(); + } + pub fn bits(&self, is_b: bool) -> usize { + if is_b { + self.colors.len() * 8 + + self.pattern.len() * 8 + + self.xoff.len() * 5 + + self.yoff.len() * 5 + + self.intradc.len() * 11 + + self.interdc.len() * 11 + + self.intraq.len() * 4 + + self.interq.len() * 4 + + self.nresidues.len() * 7 + + self.other.iter().fold(0usize, |acc, &(_, len)| acc + usize::from(len)) + } else { +unimplemented!() + } + } +} |