mirror of
https://github.com/exoticorn/upkr.git
synced 2026-01-20 19:46:42 +01:00
Compare commits
4 Commits
08c86af06f
...
parity-con
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d40bb8123 | |||
| 3902425922 | |||
| 2e7983fc65 | |||
| f7f891e154 |
@@ -6,7 +6,7 @@ const UPDATE_ADD: u32 = 8;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ContextState {
|
||||
contexts: Vec<u16>,
|
||||
contexts: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct Context<'a> {
|
||||
@@ -17,7 +17,7 @@ pub struct Context<'a> {
|
||||
impl ContextState {
|
||||
pub fn new(size: usize) -> ContextState {
|
||||
ContextState {
|
||||
contexts: vec![INIT_PROB; size],
|
||||
contexts: vec![INIT_PROB as u8; size],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,15 +28,15 @@ impl ContextState {
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
pub fn prob(&self) -> u16 {
|
||||
self.state.contexts[self.index]
|
||||
self.state.contexts[self.index] as u16
|
||||
}
|
||||
|
||||
pub fn update(&mut self, bit: bool) {
|
||||
let old = self.state.contexts[self.index];
|
||||
self.state.contexts[self.index] = if bit {
|
||||
old + ((ONE_PROB - old as u32 + UPDATE_ADD) >> UPDATE_RATE) as u16
|
||||
old + ((ONE_PROB - old as u32 + UPDATE_ADD) >> UPDATE_RATE) as u8
|
||||
} else {
|
||||
old - ((old + UPDATE_ADD as u16) >> UPDATE_RATE)
|
||||
old - ((old as u32 + UPDATE_ADD) >> UPDATE_RATE) as u8
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@ use crate::match_finder::MatchFinder;
|
||||
use crate::rans::RansCoder;
|
||||
use crate::ProgressCallback;
|
||||
|
||||
pub fn pack(data: &[u8], mut progress_callback: Option<ProgressCallback>) -> Vec<u8> {
|
||||
pub fn pack(
|
||||
data: &[u8],
|
||||
use_bitstream: bool,
|
||||
mut progress_callback: Option<ProgressCallback>,
|
||||
) -> Vec<u8> {
|
||||
let mut match_finder = MatchFinder::new(data);
|
||||
let mut rans_coder = RansCoder::new();
|
||||
let mut rans_coder = RansCoder::new(use_bitstream);
|
||||
let mut state = lz::CoderState::new();
|
||||
|
||||
let mut pos = 0;
|
||||
|
||||
13
src/lib.rs
13
src/lib.rs
@@ -2,17 +2,22 @@ mod context_state;
|
||||
mod greedy_packer;
|
||||
mod lz;
|
||||
mod match_finder;
|
||||
mod rans;
|
||||
mod parsing_packer;
|
||||
mod rans;
|
||||
|
||||
pub use lz::unpack;
|
||||
|
||||
pub type ProgressCallback<'a> = &'a mut dyn FnMut(usize);
|
||||
|
||||
pub fn pack(data: &[u8], level: u8, progress_callback: Option<ProgressCallback>) -> Vec<u8> {
|
||||
pub fn pack(
|
||||
data: &[u8],
|
||||
level: u8,
|
||||
use_bitstream: bool,
|
||||
progress_callback: Option<ProgressCallback>,
|
||||
) -> Vec<u8> {
|
||||
if level == 0 {
|
||||
greedy_packer::pack(data, progress_callback)
|
||||
greedy_packer::pack(data, use_bitstream, progress_callback)
|
||||
} else {
|
||||
parsing_packer::pack(data, level, progress_callback)
|
||||
parsing_packer::pack(data, level, use_bitstream, progress_callback)
|
||||
}
|
||||
}
|
||||
|
||||
48
src/lz.rs
48
src/lz.rs
@@ -9,29 +9,32 @@ pub enum Op {
|
||||
|
||||
impl Op {
|
||||
pub fn encode(&self, coder: &mut dyn EntropyCoder, state: &mut CoderState) {
|
||||
let base_context = 256 * (state.pos & 3);
|
||||
match self {
|
||||
&Op::Literal(lit) => {
|
||||
encode_bit(coder, state, 0, false);
|
||||
encode_bit(coder, state, base_context, false);
|
||||
let mut context_index = 1;
|
||||
for i in (0..8).rev() {
|
||||
let bit = (lit >> i) & 1 != 0;
|
||||
encode_bit(coder, state, context_index, bit);
|
||||
encode_bit(coder, state, base_context + context_index, bit);
|
||||
context_index = (context_index << 1) | bit as usize;
|
||||
}
|
||||
state.pos += 1;
|
||||
state.prev_was_match = false;
|
||||
}
|
||||
&Op::Match { offset, len } => {
|
||||
encode_bit(coder, state, 0, true);
|
||||
encode_bit(coder, state, base_context, true);
|
||||
if !state.prev_was_match {
|
||||
encode_bit(coder, state, 256, offset != state.last_offset);
|
||||
encode_bit(coder, state, 1024, offset != state.last_offset);
|
||||
} else {
|
||||
assert!(offset != state.last_offset);
|
||||
}
|
||||
if offset != state.last_offset {
|
||||
encode_length(coder, state, 257, offset + 1);
|
||||
encode_length(coder, state, 1025, offset + 1);
|
||||
state.last_offset = offset;
|
||||
}
|
||||
encode_length(coder, state, 257 + 64, len);
|
||||
encode_length(coder, state, 1025 + 64, len);
|
||||
state.pos += len as usize;
|
||||
state.prev_was_match = true;
|
||||
}
|
||||
}
|
||||
@@ -39,9 +42,11 @@ impl Op {
|
||||
}
|
||||
|
||||
pub fn encode_eof(coder: &mut dyn EntropyCoder, state: &mut CoderState) {
|
||||
encode_bit(coder, state, 0, true);
|
||||
encode_bit(coder, state, 256, true);
|
||||
encode_length(coder, state, 257, 1);
|
||||
encode_bit(coder, state, 256 * (state.pos & 3), true);
|
||||
if !state.prev_was_match {
|
||||
encode_bit(coder, state, 1024, true);
|
||||
}
|
||||
encode_length(coder, state, 1025, 1);
|
||||
}
|
||||
|
||||
fn encode_bit(
|
||||
@@ -75,15 +80,17 @@ fn encode_length(
|
||||
pub struct CoderState {
|
||||
contexts: ContextState,
|
||||
last_offset: u32,
|
||||
prev_was_match: bool
|
||||
pos: usize,
|
||||
prev_was_match: bool,
|
||||
}
|
||||
|
||||
impl CoderState {
|
||||
pub fn new() -> CoderState {
|
||||
CoderState {
|
||||
contexts: ContextState::new(1 + 255 + 1 + 64 + 64),
|
||||
contexts: ContextState::new((1 + 255) * 4 + 1 + 64 + 64),
|
||||
last_offset: 0,
|
||||
prev_was_match: false
|
||||
pos: 0,
|
||||
prev_was_match: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +99,9 @@ impl CoderState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unpack(packed_data: &[u8]) -> Vec<u8> {
|
||||
let mut decoder = RansDecoder::new(packed_data);
|
||||
let mut contexts = ContextState::new(1 + 255 + 1 + 64 + 64);
|
||||
pub fn unpack(packed_data: &[u8], use_bitstream: bool) -> Vec<u8> {
|
||||
let mut decoder = RansDecoder::new(packed_data, use_bitstream);
|
||||
let mut contexts = ContextState::new((1 + 255) * 4 + 1 + 64 + 64);
|
||||
let mut result = vec![];
|
||||
let mut offset = 0;
|
||||
let mut prev_was_match = false;
|
||||
@@ -117,14 +124,15 @@ pub fn unpack(packed_data: &[u8]) -> Vec<u8> {
|
||||
}
|
||||
|
||||
loop {
|
||||
if decoder.decode_with_context(&mut contexts.context_mut(0)) {
|
||||
if prev_was_match || decoder.decode_with_context(&mut contexts.context_mut(256)) {
|
||||
offset = decode_length(&mut decoder, &mut contexts, 257) - 1;
|
||||
let base_context = 256 * (result.len() & 3);
|
||||
if decoder.decode_with_context(&mut contexts.context_mut(base_context)) {
|
||||
if prev_was_match || decoder.decode_with_context(&mut contexts.context_mut(1024)) {
|
||||
offset = decode_length(&mut decoder, &mut contexts, 1025) - 1;
|
||||
if offset == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let length = decode_length(&mut decoder, &mut contexts, 257 + 64);
|
||||
let length = decode_length(&mut decoder, &mut contexts, 1025 + 64);
|
||||
for _ in 0..length {
|
||||
result.push(result[result.len() - offset]);
|
||||
}
|
||||
@@ -133,7 +141,7 @@ pub fn unpack(packed_data: &[u8]) -> Vec<u8> {
|
||||
let mut context_index = 1;
|
||||
let mut byte = 0;
|
||||
for i in (0..8).rev() {
|
||||
let bit = decoder.decode_with_context(&mut contexts.context_mut(context_index));
|
||||
let bit = decoder.decode_with_context(&mut contexts.context_mut(base_context + context_index));
|
||||
context_index = (context_index << 1) | bit as usize;
|
||||
byte |= (bit as u8) << i;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ fn main() -> Result<()> {
|
||||
None => print_help(),
|
||||
Some("pack") => {
|
||||
let level = args.opt_value_from_str(["-l", "--level"])?.unwrap_or(2u8);
|
||||
let use_bitstream = args.contains(["-b", "--bitstream"]);
|
||||
|
||||
let infile = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
|
||||
let outfile = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
|
||||
@@ -21,6 +22,7 @@ fn main() -> Result<()> {
|
||||
let packed_data = upkr::pack(
|
||||
&data,
|
||||
level,
|
||||
use_bitstream,
|
||||
Some(&mut |pos| {
|
||||
pb.set(pos as u64);
|
||||
}),
|
||||
@@ -36,12 +38,14 @@ fn main() -> Result<()> {
|
||||
File::create(outfile)?.write_all(&packed_data)?;
|
||||
}
|
||||
Some("unpack") => {
|
||||
let use_bitstream = args.contains(["-b", "--bitstream"]);
|
||||
|
||||
let infile = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
|
||||
let outfile = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
|
||||
|
||||
let mut data = vec![];
|
||||
File::open(infile)?.read_to_end(&mut data)?;
|
||||
let packed_data = upkr::unpack(&data);
|
||||
let packed_data = upkr::unpack(&data, use_bitstream);
|
||||
File::create(outfile)?.write_all(&packed_data)?;
|
||||
}
|
||||
Some(other) => {
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::match_finder::MatchFinder;
|
||||
use crate::rans::{CostCounter, RansCoder};
|
||||
use crate::{lz, ProgressCallback};
|
||||
|
||||
pub fn pack(data: &[u8], level: u8, progress_cb: Option<ProgressCallback>) -> Vec<u8> {
|
||||
pub fn pack(data: &[u8], level: u8, use_bitstream: bool, progress_cb: Option<ProgressCallback>) -> Vec<u8> {
|
||||
let mut parse = parse(data, Config::from_level(level), progress_cb);
|
||||
let mut ops = vec![];
|
||||
while let Some(link) = parse {
|
||||
@@ -14,7 +14,7 @@ pub fn pack(data: &[u8], level: u8, progress_cb: Option<ProgressCallback>) -> Ve
|
||||
parse = link.prev.clone();
|
||||
}
|
||||
let mut state = lz::CoderState::new();
|
||||
let mut coder = RansCoder::new();
|
||||
let mut coder = RansCoder::new(use_bitstream);
|
||||
for op in ops.into_iter().rev() {
|
||||
op.encode(&mut coder, &mut state);
|
||||
}
|
||||
|
||||
90
src/rans.rs
90
src/rans.rs
@@ -1,6 +1,5 @@
|
||||
use crate::context_state::Context;
|
||||
|
||||
const L_BITS: u32 = 12;
|
||||
pub const PROB_BITS: u32 = 8;
|
||||
pub const ONE_PROB: u32 = 1 << PROB_BITS;
|
||||
|
||||
@@ -13,43 +12,75 @@ pub trait EntropyCoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RansCoder(Vec<u16>);
|
||||
pub struct RansCoder {
|
||||
bits: Vec<u16>,
|
||||
use_bitstream: bool,
|
||||
}
|
||||
|
||||
impl EntropyCoder for RansCoder {
|
||||
fn encode_bit(&mut self, bit: bool, prob: u16) {
|
||||
assert!(prob < 32768);
|
||||
self.0.push(prob | ((bit as u16) << 15));
|
||||
self.bits.push(prob | ((bit as u16) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
impl RansCoder {
|
||||
pub fn new() -> RansCoder {
|
||||
RansCoder(Vec::new())
|
||||
pub fn new(use_bitstream: bool) -> RansCoder {
|
||||
RansCoder {
|
||||
bits: Vec::new(),
|
||||
use_bitstream,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(self) -> Vec<u8> {
|
||||
let mut buffer = vec![];
|
||||
let mut state = 1 << L_BITS;
|
||||
let l_bits: u32 = if self.use_bitstream { 15 } else { 12 };
|
||||
let mut state = 1 << l_bits;
|
||||
|
||||
const MAX_STATE_FACTOR: u32 = 1 << (L_BITS + 8 - PROB_BITS);
|
||||
for step in self.0.into_iter().rev() {
|
||||
let mut byte = 0u8;
|
||||
let mut bit = 8;
|
||||
let mut flush_state: Box<dyn FnMut(&mut u32)> = if self.use_bitstream {
|
||||
Box::new(|state: &mut u32| {
|
||||
bit -= 1;
|
||||
byte |= ((*state & 1) as u8) << bit;
|
||||
if bit == 0 {
|
||||
buffer.push(byte);
|
||||
byte = 0;
|
||||
bit = 8;
|
||||
}
|
||||
*state >>= 1;
|
||||
})
|
||||
} else {
|
||||
Box::new(|state: &mut u32| {
|
||||
buffer.push(*state as u8);
|
||||
*state >>= 8;
|
||||
})
|
||||
};
|
||||
|
||||
let num_flush_bits = if self.use_bitstream { 1 } else { 8 };
|
||||
let max_state_factor: u32 = 1 << (l_bits + num_flush_bits - PROB_BITS);
|
||||
for step in self.bits.into_iter().rev() {
|
||||
let prob = step as u32 & 32767;
|
||||
let (start, prob) = if step & 32768 != 0 {
|
||||
(0, prob)
|
||||
} else {
|
||||
(prob, ONE_PROB - prob)
|
||||
};
|
||||
let max_state = MAX_STATE_FACTOR * prob;
|
||||
let max_state = max_state_factor * prob;
|
||||
while state >= max_state {
|
||||
buffer.push(state as u8);
|
||||
state >>= 8;
|
||||
flush_state(&mut state);
|
||||
}
|
||||
state = ((state / prob) << PROB_BITS) + (state % prob) + start;
|
||||
}
|
||||
|
||||
while state > 0 {
|
||||
buffer.push(state as u8);
|
||||
state >>= 8;
|
||||
flush_state(&mut state);
|
||||
}
|
||||
|
||||
drop(flush_state);
|
||||
|
||||
if self.use_bitstream && byte != 0 {
|
||||
buffer.push(byte);
|
||||
}
|
||||
|
||||
buffer.reverse();
|
||||
@@ -99,14 +130,22 @@ impl EntropyCoder for CostCounter {
|
||||
pub struct RansDecoder<'a> {
|
||||
data: &'a [u8],
|
||||
state: u32,
|
||||
use_bitstream: bool,
|
||||
byte: u8,
|
||||
bits_left: u8,
|
||||
}
|
||||
|
||||
const PROB_MASK: u32 = ONE_PROB - 1;
|
||||
const L: u32 = 1 << L_BITS;
|
||||
|
||||
impl<'a> RansDecoder<'a> {
|
||||
pub fn new(data: &'a [u8]) -> RansDecoder<'a> {
|
||||
RansDecoder { data, state: 0 }
|
||||
pub fn new(data: &'a [u8], use_bitstream: bool) -> RansDecoder<'a> {
|
||||
RansDecoder {
|
||||
data,
|
||||
state: 0,
|
||||
use_bitstream,
|
||||
byte: 0,
|
||||
bits_left: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_with_context(&mut self, context: &mut Context) -> bool {
|
||||
@@ -117,9 +156,22 @@ impl<'a> RansDecoder<'a> {
|
||||
|
||||
pub fn decode_bit(&mut self, prob: u16) -> bool {
|
||||
let prob = prob as u32;
|
||||
while self.state < L {
|
||||
self.state = (self.state << 8) | self.data[0] as u32;
|
||||
self.data = &self.data[1..];
|
||||
if self.use_bitstream {
|
||||
while self.state < 32768 {
|
||||
if self.bits_left == 0 {
|
||||
self.byte = self.data[0];
|
||||
self.data = &self.data[1..];
|
||||
self.bits_left = 8;
|
||||
}
|
||||
self.state = (self.state << 1) | (self.byte & 1) as u32;
|
||||
self.byte >>= 1;
|
||||
self.bits_left -= 1;
|
||||
}
|
||||
} else {
|
||||
while self.state < 4096 {
|
||||
self.state = (self.state << 8) | self.data[0] as u32;
|
||||
self.data = &self.data[1..];
|
||||
}
|
||||
}
|
||||
|
||||
let bit = (self.state & PROB_MASK) < prob;
|
||||
|
||||
Reference in New Issue
Block a user