1
0
mirror of https://frontier.innolan.net/github/AmigaExamples.git synced 2026-05-10 07:07:23 +00:00
Files
AmigaExamples/tools/external/shrinkler/RangeDecoder.h
2016-03-15 16:25:03 +11:00

104 lines
2.2 KiB
C++

// Copyright 1999-2015 Aske Simon Christensen. See LICENSE.txt for usage terms.
/*
A decoder for the range coder.
*/
#pragma once
#include <cmath>
#include <algorithm>
#include <vector>
using std::fill;
using std::vector;
#include "Decoder.h"
#include "assert.h"
#ifndef ADJUST_SHIFT
#define ADJUST_SHIFT 4
#endif
class CompressedDataReadListener {
public:
virtual void read(int index) = 0;
virtual ~CompressedDataReadListener() {}
};
class RangeDecoder : public Decoder {
vector<unsigned short> contexts;
vector<unsigned>& data;
CompressedDataReadListener* listener;
int bit_index;
unsigned intervalsize;
unsigned intervalvalue;
unsigned uncertainty;
int getBit() {
int long_index = bit_index >> 5;
int bit_in_long = (~bit_index) & 31;
if (bit_in_long == 31) {
if (listener) listener->read(long_index);
}
if (bit_index++ >= data.size() * 32) {
uncertainty <<= 1;
return 0;
}
int bit = (data[long_index] >> bit_in_long) & 1;
return bit;
}
public:
RangeDecoder(int n_contexts, vector<unsigned>& data) : data(data) {
contexts.resize(n_contexts, 0x8000);
bit_index = 0;
intervalsize = 1;
intervalvalue = 0;
uncertainty = 1;
listener = NULL;
}
virtual int decode(int context_index) {
assert(context_index < contexts.size());
unsigned prob = contexts[context_index];
while (intervalsize < 0x8000) {
intervalsize <<= 1;
intervalvalue = (intervalvalue << 1) | getBit();
}
int bit;
unsigned new_prob;
unsigned threshold = (intervalsize * prob) >> 16;
if (intervalvalue >= threshold) {
// Zero
bit = 0;
intervalvalue -= threshold;
intervalsize -= threshold;
new_prob = prob - (prob >> ADJUST_SHIFT);
} else {
// One
assert(intervalvalue + uncertainty <= threshold);
bit = 1;
intervalsize = threshold;
new_prob = prob + (0xffff >> ADJUST_SHIFT) - (prob >> ADJUST_SHIFT);
}
assert(new_prob > 0);
assert(new_prob < 0x10000);
contexts[context_index] = new_prob;
return bit;
}
void reset() {
fill(contexts.begin(), contexts.end(), 0x8000);
}
void setListener(CompressedDataReadListener* listener) {
this->listener = listener;
}
};