Files
unity/crnlib/crn_symbol_codec.cpp
T
Alexander Suvorov 3e12aff909 Fix miscellaneous compiler warnings
DXT Testing:

The modified algorithm has been tested on the Kodak test set using 64-bit build with default settings (running on Windows 10, i7-4790, 3.6GHz). All the decompressed test images are identical to the images being compressed and decompressed using original version of Crunch (revision ea9b8d8).

[Compressing Kodak set without mipmaps using DXT1 encoding]
Original: 1582222 bytes / 28.866 sec
Modified: 1468204 bytes / 11.858 sec
Improvement: 7.21% (compression ratio) / 58.92% (compression time)

[Compressing Kodak set with mipmaps using DXT1 encoding]
Original: 2065243 bytes / 36.878 sec
Modified: 1914805 bytes / 15.625 sec
Improvement: 7.28% (compression ratio) / 57.63% (compression time)

ETC Testing:

The modified algorithm has been tested on the Kodak test set using 64-bit build with default settings (running on Windows 10, i7-4790, 3.6GHz). The ETC1 quantization parameters have been selected in such a way, so that ETC1 compression gives approximately the same average Luma PSNR as the corresponding DXT1 compression (which is equal to 34.044 dB for the Kodak test set compressed without mipmaps using DXT1 encoding and default quality settings).

[Compressing Kodak set without mipmaps using ETC1 encoding]
Total size: 1607858 bytes
Total time: 17.181 sec
Average bitrate: 1.363 bpp
Average Luma PSNR: 34.050 dB
2017-09-11 13:52:21 +02:00

1668 lines
44 KiB
C++

// File: crn_symbol_codec.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_symbol_codec.h"
#include "crn_huffman_codes.h"
namespace crnlib {
static float gProbCost[cSymbolCodecArithProbScale];
//const uint cArithProbMulLenSigBits = 8;
//const uint cArithProbMulLenSigScale = 1 << cArithProbMulLenSigBits;
class arith_prob_cost_initializer {
public:
arith_prob_cost_initializer() {
const float cInvLn2 = 1.0f / 0.69314718f;
for (uint i = 0; i < cSymbolCodecArithProbScale; i++)
gProbCost[i] = -logf(i * (1.0f / cSymbolCodecArithProbScale)) * cInvLn2;
}
};
static arith_prob_cost_initializer g_prob_cost_initializer;
double symbol_histogram::calc_entropy() const {
double total = 0.0f;
for (uint i = 0; i < m_hist.size(); i++)
total += m_hist[i];
if (total == 0.0f)
return 0.0f;
double entropy = 0.0f;
double neg_inv_log2 = -1.0f / log(2.0f);
double inv_total = 1.0f / total;
for (uint i = 0; i < m_hist.size(); i++) {
if (m_hist[i]) {
double bits = log(m_hist[i] * inv_total) * neg_inv_log2;
entropy += bits * m_hist[i];
}
}
return entropy;
}
uint64 symbol_histogram::get_total() const {
uint64 total = 0;
for (uint i = 0; i < m_hist.size(); i++)
total += m_hist[i];
return total;
}
adaptive_huffman_data_model::adaptive_huffman_data_model(bool encoding, uint total_syms)
: m_total_syms(0),
m_update_cycle(0),
m_symbols_until_update(0),
m_total_count(0),
m_pDecode_tables(NULL),
m_decoder_table_bits(0),
m_encoding(encoding) {
if (total_syms)
init(encoding, total_syms);
}
adaptive_huffman_data_model::adaptive_huffman_data_model(const adaptive_huffman_data_model& other)
: m_total_syms(0),
m_update_cycle(0),
m_symbols_until_update(0),
m_total_count(0),
m_pDecode_tables(NULL),
m_decoder_table_bits(0),
m_encoding(false) {
*this = other;
}
adaptive_huffman_data_model::~adaptive_huffman_data_model() {
if (m_pDecode_tables)
crnlib_delete(m_pDecode_tables);
}
adaptive_huffman_data_model& adaptive_huffman_data_model::operator=(const adaptive_huffman_data_model& rhs) {
if (this == &rhs)
return *this;
m_total_syms = rhs.m_total_syms;
m_update_cycle = rhs.m_update_cycle;
m_symbols_until_update = rhs.m_symbols_until_update;
m_total_count = rhs.m_total_count;
m_sym_freq = rhs.m_sym_freq;
m_codes = rhs.m_codes;
m_code_sizes = rhs.m_code_sizes;
if (rhs.m_pDecode_tables) {
if (m_pDecode_tables)
*m_pDecode_tables = *rhs.m_pDecode_tables;
else
m_pDecode_tables = crnlib_new<prefix_coding::decoder_tables>(*rhs.m_pDecode_tables);
} else {
crnlib_delete(m_pDecode_tables);
m_pDecode_tables = NULL;
}
m_decoder_table_bits = rhs.m_decoder_table_bits;
m_encoding = rhs.m_encoding;
return *this;
}
void adaptive_huffman_data_model::clear() {
m_sym_freq.clear();
m_codes.clear();
m_code_sizes.clear();
m_total_syms = 0;
m_update_cycle = 0;
m_symbols_until_update = 0;
m_decoder_table_bits = 0;
m_total_count = 0;
if (m_pDecode_tables) {
crnlib_delete(m_pDecode_tables);
m_pDecode_tables = NULL;
}
}
void adaptive_huffman_data_model::init(bool encoding, uint total_syms) {
clear();
m_encoding = encoding;
m_sym_freq.resize(total_syms);
m_code_sizes.resize(total_syms);
m_total_syms = total_syms;
if (m_total_syms <= 16)
m_decoder_table_bits = 0;
else
m_decoder_table_bits = static_cast<uint8>(math::minimum(1 + math::ceil_log2i(m_total_syms), prefix_coding::cMaxTableBits));
if (m_encoding)
m_codes.resize(total_syms);
else
m_pDecode_tables = crnlib_new<prefix_coding::decoder_tables>();
reset();
}
void adaptive_huffman_data_model::reset() {
if (!m_total_syms)
return;
for (uint i = 0; i < m_total_syms; i++)
m_sym_freq[i] = 1;
m_total_count = 0;
m_update_cycle = m_total_syms;
update();
m_symbols_until_update = m_update_cycle = 8; //(m_total_syms + 6) >> 1;
}
void adaptive_huffman_data_model::rescale() {
uint total_freq = 0;
for (uint i = 0; i < m_total_syms; i++) {
uint freq = (m_sym_freq[i] + 1) >> 1;
total_freq += freq;
m_sym_freq[i] = static_cast<uint16>(freq);
}
m_total_count = total_freq;
}
void adaptive_huffman_data_model::update() {
m_total_count += m_update_cycle;
if (m_total_count >= 32768)
rescale();
void* pTables = create_generate_huffman_codes_tables();
uint max_code_size, total_freq;
bool status = generate_huffman_codes(pTables, m_total_syms, &m_sym_freq[0], &m_code_sizes[0], max_code_size, total_freq);
CRNLIB_ASSERT(status);
CRNLIB_ASSERT(total_freq == m_total_count);
if (max_code_size > prefix_coding::cMaxExpectedCodeSize)
prefix_coding::limit_max_code_size(m_total_syms, &m_code_sizes[0], prefix_coding::cMaxExpectedCodeSize);
free_generate_huffman_codes_tables(pTables);
if (m_encoding)
status = prefix_coding::generate_codes(m_total_syms, &m_code_sizes[0], &m_codes[0]);
else
status = prefix_coding::generate_decoder_tables(m_total_syms, &m_code_sizes[0], m_pDecode_tables, m_decoder_table_bits);
CRNLIB_ASSERT(status);
(void)status;
m_update_cycle = (5 * m_update_cycle) >> 2;
uint max_cycle = (m_total_syms + 6) << 3; // this was << 2 - which is ~12% slower but compresses around .5% better
if (m_update_cycle > max_cycle)
m_update_cycle = max_cycle;
m_symbols_until_update = m_update_cycle;
}
static_huffman_data_model::static_huffman_data_model()
: m_total_syms(0),
m_pDecode_tables(NULL),
m_encoding(false) {
}
static_huffman_data_model::static_huffman_data_model(const static_huffman_data_model& other)
: m_total_syms(0),
m_pDecode_tables(NULL),
m_encoding(false) {
*this = other;
}
static_huffman_data_model::~static_huffman_data_model() {
if (m_pDecode_tables)
crnlib_delete(m_pDecode_tables);
}
static_huffman_data_model& static_huffman_data_model::operator=(const static_huffman_data_model& rhs) {
if (this == &rhs)
return *this;
m_total_syms = rhs.m_total_syms;
m_codes = rhs.m_codes;
m_code_sizes = rhs.m_code_sizes;
if (rhs.m_pDecode_tables) {
if (m_pDecode_tables)
*m_pDecode_tables = *rhs.m_pDecode_tables;
else
m_pDecode_tables = crnlib_new<prefix_coding::decoder_tables>(*rhs.m_pDecode_tables);
} else {
crnlib_delete(m_pDecode_tables);
m_pDecode_tables = NULL;
}
m_encoding = rhs.m_encoding;
return *this;
}
void static_huffman_data_model::clear() {
m_total_syms = 0;
m_codes.clear();
m_code_sizes.clear();
if (m_pDecode_tables) {
crnlib_delete(m_pDecode_tables);
m_pDecode_tables = NULL;
}
m_encoding = false;
}
bool static_huffman_data_model::init(bool encoding, uint total_syms, const uint16* pSym_freq, uint code_size_limit) {
CRNLIB_ASSERT((total_syms >= 1) && (total_syms <= prefix_coding::cMaxSupportedSyms) && (code_size_limit >= 1));
m_encoding = encoding;
m_total_syms = total_syms;
code_size_limit = math::minimum(code_size_limit, prefix_coding::cMaxExpectedCodeSize);
m_code_sizes.resize(total_syms);
void* pTables = create_generate_huffman_codes_tables();
uint max_code_size = 0, total_freq;
bool status = generate_huffman_codes(pTables, m_total_syms, pSym_freq, &m_code_sizes[0], max_code_size, total_freq);
free_generate_huffman_codes_tables(pTables);
if (!status)
return false;
if (max_code_size > code_size_limit) {
if (!prefix_coding::limit_max_code_size(m_total_syms, &m_code_sizes[0], code_size_limit))
return false;
}
if (m_encoding) {
m_codes.resize(total_syms);
if (m_pDecode_tables) {
crnlib_delete(m_pDecode_tables);
m_pDecode_tables = NULL;
}
if (!prefix_coding::generate_codes(m_total_syms, &m_code_sizes[0], &m_codes[0]))
return false;
} else {
m_codes.clear();
if (!m_pDecode_tables)
m_pDecode_tables = crnlib_new<prefix_coding::decoder_tables>();
if (!prefix_coding::generate_decoder_tables(m_total_syms, &m_code_sizes[0], m_pDecode_tables, compute_decoder_table_bits()))
return false;
}
return true;
}
bool static_huffman_data_model::init(bool encoding, uint total_syms, const uint* pSym_freq, uint code_size_limit) {
CRNLIB_ASSERT((total_syms >= 1) && (total_syms <= prefix_coding::cMaxSupportedSyms) && (code_size_limit >= 1));
crnlib::vector<uint16> sym_freq16(total_syms);
uint max_freq = 0;
for (uint i = 0; i < total_syms; i++)
max_freq = math::maximum(max_freq, pSym_freq[i]);
if (!max_freq)
return false;
if (max_freq <= cUINT16_MAX) {
for (uint i = 0; i < total_syms; i++)
sym_freq16[i] = static_cast<uint16>(pSym_freq[i]);
} else {
for (uint i = 0; i < total_syms; i++) {
uint f = pSym_freq[i];
if (!f)
continue;
uint64 fl = f;
fl = ((fl << 16) - fl) + (max_freq >> 1);
fl /= max_freq;
if (fl < 1)
fl = 1;
CRNLIB_ASSERT(fl <= cUINT16_MAX);
sym_freq16[i] = static_cast<uint16>(fl);
}
}
return init(encoding, total_syms, &sym_freq16[0], code_size_limit);
}
bool static_huffman_data_model::init(bool encoding, uint total_syms, const uint8* pCode_sizes, uint code_size_limit) {
CRNLIB_ASSERT((total_syms >= 1) && (total_syms <= prefix_coding::cMaxSupportedSyms) && (code_size_limit >= 1));
m_encoding = encoding;
code_size_limit = math::minimum(code_size_limit, prefix_coding::cMaxExpectedCodeSize);
m_code_sizes.resize(total_syms);
uint min_code_size = UINT_MAX;
uint max_code_size = 0;
for (uint i = 0; i < total_syms; i++) {
uint s = pCode_sizes[i];
m_code_sizes[i] = static_cast<uint8>(s);
min_code_size = math::minimum(min_code_size, s);
max_code_size = math::maximum(max_code_size, s);
}
if ((max_code_size < 1) || (max_code_size > 32) || (min_code_size > code_size_limit))
return false;
if (max_code_size > code_size_limit) {
if (!prefix_coding::limit_max_code_size(m_total_syms, &m_code_sizes[0], code_size_limit))
return false;
}
if (m_encoding) {
m_codes.resize(total_syms);
if (m_pDecode_tables) {
crnlib_delete(m_pDecode_tables);
m_pDecode_tables = NULL;
}
if (!prefix_coding::generate_codes(m_total_syms, &m_code_sizes[0], &m_codes[0]))
return false;
} else {
m_codes.clear();
if (!m_pDecode_tables)
m_pDecode_tables = crnlib_new<prefix_coding::decoder_tables>();
if (!prefix_coding::generate_decoder_tables(m_total_syms, &m_code_sizes[0], m_pDecode_tables, compute_decoder_table_bits()))
return false;
}
return true;
}
bool static_huffman_data_model::init(bool encoding, const symbol_histogram& hist, uint code_size_limit) {
return init(encoding, hist.size(), hist.get_ptr(), code_size_limit);
}
bool static_huffman_data_model::prepare_decoder_tables() {
uint total_syms = m_code_sizes.size();
CRNLIB_ASSERT((total_syms >= 1) && (total_syms <= prefix_coding::cMaxSupportedSyms));
m_encoding = false;
m_total_syms = total_syms;
m_codes.clear();
if (!m_pDecode_tables)
m_pDecode_tables = crnlib_new<prefix_coding::decoder_tables>();
return prefix_coding::generate_decoder_tables(m_total_syms, &m_code_sizes[0], m_pDecode_tables, compute_decoder_table_bits());
}
uint static_huffman_data_model::compute_decoder_table_bits() const {
uint decoder_table_bits = 0;
if (m_total_syms > 16)
decoder_table_bits = static_cast<uint8>(math::minimum(1 + math::ceil_log2i(m_total_syms), prefix_coding::cMaxTableBits));
return decoder_table_bits;
}
adaptive_bit_model::adaptive_bit_model() {
clear();
}
adaptive_bit_model::adaptive_bit_model(float prob0) {
set_probability_0(prob0);
}
adaptive_bit_model::adaptive_bit_model(const adaptive_bit_model& other)
: m_bit_0_prob(other.m_bit_0_prob) {
}
adaptive_bit_model& adaptive_bit_model::operator=(const adaptive_bit_model& rhs) {
m_bit_0_prob = rhs.m_bit_0_prob;
return *this;
}
void adaptive_bit_model::clear() {
m_bit_0_prob = 1U << (cSymbolCodecArithProbBits - 1);
}
void adaptive_bit_model::set_probability_0(float prob0) {
m_bit_0_prob = static_cast<uint16>(math::clamp<uint>((uint)(prob0 * cSymbolCodecArithProbScale), 1, cSymbolCodecArithProbScale - 1));
}
float adaptive_bit_model::get_cost(uint bit) const {
return gProbCost[bit ? (cSymbolCodecArithProbScale - m_bit_0_prob) : m_bit_0_prob];
}
void adaptive_bit_model::update(uint bit) {
if (!bit)
m_bit_0_prob += ((cSymbolCodecArithProbScale - m_bit_0_prob) >> cSymbolCodecArithProbMoveBits);
else
m_bit_0_prob -= (m_bit_0_prob >> cSymbolCodecArithProbMoveBits);
CRNLIB_ASSERT(m_bit_0_prob >= 1);
CRNLIB_ASSERT(m_bit_0_prob < cSymbolCodecArithProbScale);
}
adaptive_arith_data_model::adaptive_arith_data_model(bool encoding, uint total_syms) {
init(encoding, total_syms);
}
adaptive_arith_data_model::adaptive_arith_data_model(const adaptive_arith_data_model& other) {
m_total_syms = other.m_total_syms;
m_probs = other.m_probs;
}
adaptive_arith_data_model::~adaptive_arith_data_model() {
}
adaptive_arith_data_model& adaptive_arith_data_model::operator=(const adaptive_arith_data_model& rhs) {
m_total_syms = rhs.m_total_syms;
m_probs = rhs.m_probs;
return *this;
}
void adaptive_arith_data_model::clear() {
m_total_syms = 0;
m_probs.clear();
}
void adaptive_arith_data_model::init(bool, uint total_syms) {
if (!total_syms) {
clear();
return;
}
if ((total_syms < 2) || (!math::is_power_of_2(total_syms)))
total_syms = math::next_pow2(total_syms);
m_total_syms = total_syms;
m_probs.resize(m_total_syms);
}
void adaptive_arith_data_model::reset() {
for (uint i = 0; i < m_probs.size(); i++)
m_probs[i].clear();
}
float adaptive_arith_data_model::get_cost(uint sym) const {
uint node = 1;
uint bitmask = m_total_syms;
float cost = 0.0f;
do {
bitmask >>= 1;
uint bit = (sym & bitmask) ? 1 : 0;
cost += m_probs[node].get_cost(bit);
node = (node << 1) + bit;
} while (bitmask > 1);
return cost;
}
symbol_codec::symbol_codec() {
clear();
}
void symbol_codec::clear() {
m_pDecode_buf = NULL;
m_pDecode_buf_next = NULL;
m_pDecode_buf_end = NULL;
m_decode_buf_size = 0;
m_bit_buf = 0;
m_bit_count = 0;
m_total_model_updates = 0;
m_mode = cNull;
m_simulate_encoding = false;
m_total_bits_written = 0;
m_arith_base = 0;
m_arith_value = 0;
m_arith_length = 0;
m_arith_total_bits = 0;
m_output_buf.clear();
m_arith_output_buf.clear();
m_output_syms.clear();
}
void symbol_codec::start_encoding(uint expected_file_size) {
m_mode = cEncoding;
m_total_model_updates = 0;
m_total_bits_written = 0;
put_bits_init(expected_file_size);
m_output_syms.resize(0);
arith_start_encoding();
}
// Code length encoding symbols:
// 0-16 - actual code lengths
const uint cMaxCodelengthCodes = 21;
const uint cSmallZeroRunCode = 17;
const uint cLargeZeroRunCode = 18;
const uint cSmallRepeatCode = 19;
const uint cLargeRepeatCode = 20;
const uint cMinSmallZeroRunSize = 3;
const uint cMaxSmallZeroRunSize = 10;
const uint cMinLargeZeroRunSize = 11;
const uint cMaxLargeZeroRunSize = 138;
const uint cSmallMinNonZeroRunSize = 3;
const uint cSmallMaxNonZeroRunSize = 6;
const uint cLargeMinNonZeroRunSize = 7;
const uint cLargeMaxNonZeroRunSize = 70;
const uint cSmallZeroRunExtraBits = 3;
const uint cLargeZeroRunExtraBits = 7;
const uint cSmallNonZeroRunExtraBits = 2;
const uint cLargeNonZeroRunExtraBits = 6;
static const uint8 g_most_probable_codelength_codes[] =
{
cSmallZeroRunCode, cLargeZeroRunCode,
cSmallRepeatCode, cLargeRepeatCode,
0, 8,
7, 9,
6, 10,
5, 11,
4, 12,
3, 13,
2, 14,
1, 15,
16};
const uint cNumMostProbableCodelengthCodes = sizeof(g_most_probable_codelength_codes) / sizeof(g_most_probable_codelength_codes[0]);
static inline void end_zero_run(uint& size, crnlib::vector<uint16>& codes) {
if (!size)
return;
if (size < cMinSmallZeroRunSize) {
while (size--)
codes.push_back(0);
} else if (size <= cMaxSmallZeroRunSize)
codes.push_back(static_cast<uint16>(cSmallZeroRunCode | ((size - cMinSmallZeroRunSize) << 8)));
else {
CRNLIB_ASSERT((size >= cMinLargeZeroRunSize) && (size <= cMaxLargeZeroRunSize));
codes.push_back(static_cast<uint16>(cLargeZeroRunCode | ((size - cMinLargeZeroRunSize) << 8)));
}
size = 0;
}
static inline void end_nonzero_run(uint& size, uint len, crnlib::vector<uint16>& codes) {
if (!size)
return;
if (size < cSmallMinNonZeroRunSize) {
while (size--)
codes.push_back(static_cast<uint16>(len));
} else if (size <= cSmallMaxNonZeroRunSize) {
codes.push_back(static_cast<uint16>(cSmallRepeatCode | ((size - cSmallMinNonZeroRunSize) << 8)));
} else {
CRNLIB_ASSERT((size >= cLargeMinNonZeroRunSize) && (size <= cLargeMaxNonZeroRunSize));
codes.push_back(static_cast<uint16>(cLargeRepeatCode | ((size - cLargeMinNonZeroRunSize) << 8)));
}
size = 0;
}
uint symbol_codec::encode_transmit_static_huffman_data_model(static_huffman_data_model& model, bool simulate = false, static_huffman_data_model* pDeltaModel) {
CRNLIB_ASSERT(m_mode == cEncoding);
uint total_used_syms = 0;
for (uint i = model.m_total_syms; i > 0; i--) {
if (model.m_code_sizes[i - 1]) {
total_used_syms = i;
break;
}
}
if (!total_used_syms) {
if (!simulate) {
encode_bits(0, math::total_bits(prefix_coding::cMaxSupportedSyms));
}
return math::total_bits(prefix_coding::cMaxSupportedSyms);
}
crnlib::vector<uint16> codes;
codes.reserve(model.m_total_syms);
uint prev_len = UINT_MAX;
uint cur_zero_run_size = 0;
uint cur_nonzero_run_size = 0;
const uint8* pCodesizes = &model.m_code_sizes[0];
crnlib::vector<uint8> delta_code_sizes;
if ((pDeltaModel) && (pDeltaModel->get_total_syms())) {
if (pDeltaModel->m_code_sizes.size() < total_used_syms)
return 0;
delta_code_sizes.resize(total_used_syms);
for (uint i = 0; i < total_used_syms; i++) {
int delta = (int)model.m_code_sizes[i] - (int)pDeltaModel->m_code_sizes[i];
if (delta < 0)
delta += 17;
delta_code_sizes[i] = static_cast<uint8>(delta);
}
pCodesizes = delta_code_sizes.get_ptr();
}
for (uint i = 0; i <= total_used_syms; i++) {
const uint len = (i < total_used_syms) ? *pCodesizes++ : 0xFF;
CRNLIB_ASSERT((len == 0xFF) || (len <= prefix_coding::cMaxExpectedCodeSize));
if (!len) {
end_nonzero_run(cur_nonzero_run_size, prev_len, codes);
if (++cur_zero_run_size == cMaxLargeZeroRunSize)
end_zero_run(cur_zero_run_size, codes);
} else {
end_zero_run(cur_zero_run_size, codes);
if (len != prev_len) {
end_nonzero_run(cur_nonzero_run_size, prev_len, codes);
if (len != 0xFF)
codes.push_back(static_cast<uint16>(len));
} else if (++cur_nonzero_run_size == cLargeMaxNonZeroRunSize)
end_nonzero_run(cur_nonzero_run_size, prev_len, codes);
}
prev_len = len;
}
uint16 hist[cMaxCodelengthCodes];
utils::zero_object(hist);
for (uint i = 0; i < codes.size(); i++) {
uint code = codes[i] & 0xFF;
CRNLIB_ASSERT(code < cMaxCodelengthCodes);
hist[code] = static_cast<uint16>(hist[code] + 1);
}
static_huffman_data_model dm;
if (!dm.init(true, cMaxCodelengthCodes, hist, 7))
return 0;
uint num_codelength_codes_to_send;
for (num_codelength_codes_to_send = cNumMostProbableCodelengthCodes; num_codelength_codes_to_send > 0; num_codelength_codes_to_send--)
if (dm.get_cost(g_most_probable_codelength_codes[num_codelength_codes_to_send - 1]))
break;
uint total_bits = math::total_bits(prefix_coding::cMaxSupportedSyms);
total_bits += 5;
total_bits += 3 * num_codelength_codes_to_send;
if (!simulate) {
encode_bits(total_used_syms, math::total_bits(prefix_coding::cMaxSupportedSyms));
encode_bits(num_codelength_codes_to_send, 5);
for (uint i = 0; i < num_codelength_codes_to_send; i++)
encode_bits(dm.get_cost(g_most_probable_codelength_codes[i]), 3);
}
for (uint i = 0; i < codes.size(); i++) {
uint code = codes[i];
uint extra = code >> 8;
code &= 0xFF;
uint extra_bits = 0;
if (code == cSmallZeroRunCode)
extra_bits = cSmallZeroRunExtraBits;
else if (code == cLargeZeroRunCode)
extra_bits = cLargeZeroRunExtraBits;
else if (code == cSmallRepeatCode)
extra_bits = cSmallNonZeroRunExtraBits;
else if (code == cLargeRepeatCode)
extra_bits = cLargeNonZeroRunExtraBits;
total_bits += dm.get_cost(code);
if (!simulate)
encode(code, dm);
if (extra_bits) {
if (!simulate)
encode_bits(extra, extra_bits);
total_bits += extra_bits;
}
}
return total_bits;
}
void symbol_codec::encode_bits(uint bits, uint num_bits) {
CRNLIB_ASSERT(m_mode == cEncoding);
if (!num_bits)
return;
CRNLIB_ASSERT((num_bits == 32) || (bits <= ((1U << num_bits) - 1)));
if (num_bits > 16) {
record_put_bits(bits >> 16, num_bits - 16);
record_put_bits(bits & 0xFFFF, 16);
} else
record_put_bits(bits, num_bits);
}
void symbol_codec::encode_align_to_byte() {
CRNLIB_ASSERT(m_mode == cEncoding);
if (!m_simulate_encoding) {
output_symbol sym;
sym.m_bits = 0;
sym.m_num_bits = output_symbol::cAlignToByteSym;
sym.m_arith_prob0 = 0;
m_output_syms.push_back(sym);
} else {
// We really don't know how many we're going to write, so just be conservative.
m_total_bits_written += 7;
}
}
void symbol_codec::encode(uint sym, adaptive_huffman_data_model& model) {
CRNLIB_ASSERT(m_mode == cEncoding);
CRNLIB_ASSERT(model.m_encoding);
record_put_bits(model.m_codes[sym], model.m_code_sizes[sym]);
uint freq = model.m_sym_freq[sym];
freq++;
model.m_sym_freq[sym] = static_cast<uint16>(freq);
if (freq == cUINT16_MAX)
model.rescale();
if (--model.m_symbols_until_update == 0) {
m_total_model_updates++;
model.update();
}
}
void symbol_codec::encode(uint sym, static_huffman_data_model& model) {
CRNLIB_ASSERT(m_mode == cEncoding);
CRNLIB_ASSERT(model.m_encoding);
CRNLIB_ASSERT(model.m_code_sizes[sym]);
record_put_bits(model.m_codes[sym], model.m_code_sizes[sym]);
}
void symbol_codec::encode_truncated_binary(uint v, uint n) {
CRNLIB_ASSERT((n >= 2) && (v < n));
uint k = math::floor_log2i(n);
uint u = (1 << (k + 1)) - n;
if (v < u)
encode_bits(v, k);
else
encode_bits(v + u, k + 1);
}
uint symbol_codec::encode_truncated_binary_cost(uint v, uint n) {
CRNLIB_ASSERT((n >= 2) && (v < n));
uint k = math::floor_log2i(n);
uint u = (1 << (k + 1)) - n;
if (v < u)
return k;
else
return k + 1;
}
void symbol_codec::encode_golomb(uint v, uint m) {
CRNLIB_ASSERT(m > 0);
uint q = v / m;
uint r = v % m;
while (q > 16) {
encode_bits(0xFFFF, 16);
q -= 16;
}
if (q)
encode_bits((1 << q) - 1, q);
encode_bits(0, 1);
encode_truncated_binary(r, m);
}
void symbol_codec::encode_rice(uint v, uint m) {
CRNLIB_ASSERT(m > 0);
uint q = v >> m;
uint r = v & ((1 << m) - 1);
while (q > 16) {
encode_bits(0xFFFF, 16);
q -= 16;
}
if (q)
encode_bits((1 << q) - 1, q);
encode_bits(0, 1);
encode_bits(r, m);
}
uint symbol_codec::encode_rice_get_cost(uint v, uint m) {
CRNLIB_ASSERT(m > 0);
uint q = v >> m;
//uint r = v & ((1 << m) - 1);
return q + 1 + m;
}
void symbol_codec::arith_propagate_carry() {
int index = m_arith_output_buf.size() - 1;
while (index >= 0) {
uint c = m_arith_output_buf[index];
if (c == 0xFF)
m_arith_output_buf[index] = 0;
else {
m_arith_output_buf[index]++;
break;
}
index--;
}
}
void symbol_codec::arith_renorm_enc_interval() {
do {
m_arith_output_buf.push_back((m_arith_base >> 24) & 0xFF);
m_total_bits_written += 8;
m_arith_base <<= 8;
} while ((m_arith_length <<= 8) < cSymbolCodecArithMinLen);
}
void symbol_codec::arith_start_encoding() {
m_arith_output_buf.resize(0);
m_arith_base = 0;
m_arith_value = 0;
m_arith_length = cSymbolCodecArithMaxLen;
m_arith_total_bits = 0;
}
void symbol_codec::encode(uint bit, adaptive_bit_model& model, bool update_model) {
CRNLIB_ASSERT(m_mode == cEncoding);
m_arith_total_bits++;
if (!m_simulate_encoding) {
output_symbol sym;
sym.m_bits = bit;
sym.m_num_bits = -1;
sym.m_arith_prob0 = model.m_bit_0_prob;
m_output_syms.push_back(sym);
}
//uint x = gArithProbMulTab[model.m_bit_0_prob >> (cSymbolCodecArithProbBits - cSymbolCodecArithProbMulBits)][m_arith_length >> (32 - cSymbolCodecArithProbMulLenSigBits)] << 16;
uint x = model.m_bit_0_prob * (m_arith_length >> cSymbolCodecArithProbBits);
if (!bit) {
if (update_model)
model.m_bit_0_prob += ((cSymbolCodecArithProbScale - model.m_bit_0_prob) >> cSymbolCodecArithProbMoveBits);
m_arith_length = x;
} else {
if (update_model)
model.m_bit_0_prob -= (model.m_bit_0_prob >> cSymbolCodecArithProbMoveBits);
uint orig_base = m_arith_base;
m_arith_base += x;
m_arith_length -= x;
if (orig_base > m_arith_base)
arith_propagate_carry();
}
if (m_arith_length < cSymbolCodecArithMinLen)
arith_renorm_enc_interval();
}
void symbol_codec::encode(uint sym, adaptive_arith_data_model& model) {
uint node = 1;
uint bitmask = model.m_total_syms;
do {
bitmask >>= 1;
uint bit = (sym & bitmask) ? 1 : 0;
encode(bit, model.m_probs[node]);
node = (node << 1) + bit;
} while (bitmask > 1);
}
void symbol_codec::arith_stop_encoding() {
if (!m_arith_total_bits)
return;
uint orig_base = m_arith_base;
if (m_arith_length > 2 * cSymbolCodecArithMinLen) {
m_arith_base += cSymbolCodecArithMinLen;
m_arith_length = (cSymbolCodecArithMinLen >> 1);
} else {
m_arith_base += (cSymbolCodecArithMinLen >> 1);
m_arith_length = (cSymbolCodecArithMinLen >> 9);
}
if (orig_base > m_arith_base)
arith_propagate_carry();
arith_renorm_enc_interval();
while (m_arith_output_buf.size() < 4) {
m_arith_output_buf.push_back(0);
m_total_bits_written += 8;
}
}
void symbol_codec::stop_encoding(bool support_arith) {
CRNLIB_ASSERT(m_mode == cEncoding);
arith_stop_encoding();
if (!m_simulate_encoding)
assemble_output_buf(support_arith);
m_mode = cNull;
}
void symbol_codec::record_put_bits(uint bits, uint num_bits) {
CRNLIB_ASSERT(m_mode == cEncoding);
CRNLIB_ASSERT(num_bits <= 25);
CRNLIB_ASSERT(m_bit_count >= 25);
if (!num_bits)
return;
m_total_bits_written += num_bits;
if (!m_simulate_encoding) {
output_symbol sym;
sym.m_bits = bits;
sym.m_num_bits = (uint16)num_bits;
sym.m_arith_prob0 = 0;
m_output_syms.push_back(sym);
}
}
void symbol_codec::put_bits_init(uint expected_size) {
m_bit_buf = 0;
m_bit_count = cBitBufSize;
m_output_buf.resize(0);
m_output_buf.reserve(expected_size);
}
void symbol_codec::put_bits(uint bits, uint num_bits) {
CRNLIB_ASSERT(num_bits <= 25);
CRNLIB_ASSERT(m_bit_count >= 25);
if (!num_bits)
return;
m_bit_count -= num_bits;
m_bit_buf |= (static_cast<bit_buf_t>(bits) << m_bit_count);
m_total_bits_written += num_bits;
while (m_bit_count <= (cBitBufSize - 8)) {
m_output_buf.push_back(static_cast<uint8>(m_bit_buf >> (cBitBufSize - 8)));
m_bit_buf <<= 8;
m_bit_count += 8;
}
}
void symbol_codec::put_bits_align_to_byte() {
uint num_bits_in = cBitBufSize - m_bit_count;
if (num_bits_in & 7) {
put_bits(0, 8 - (num_bits_in & 7));
}
}
void symbol_codec::flush_bits() {
//put_bits(15, 4); // for table look-ahead
//put_bits(3, 3); // for table look-ahead
put_bits(0, 7); // to ensure the last bits are flushed
}
void symbol_codec::assemble_output_buf(bool support_arith) {
m_total_bits_written = 0;
uint arith_buf_ofs = 0;
if (support_arith) {
if (m_arith_output_buf.size()) {
put_bits(1, 1);
m_arith_length = cSymbolCodecArithMaxLen;
m_arith_value = 0;
for (uint i = 0; i < 4; i++) {
const uint c = m_arith_output_buf[arith_buf_ofs++];
m_arith_value = (m_arith_value << 8) | c;
put_bits(c, 8);
}
} else {
put_bits(0, 1);
}
}
for (uint sym_index = 0; sym_index < m_output_syms.size(); sym_index++) {
const output_symbol& sym = m_output_syms[sym_index];
if (sym.m_num_bits == output_symbol::cAlignToByteSym) {
put_bits_align_to_byte();
} else if (sym.m_num_bits == output_symbol::cArithSym) {
if (m_arith_length < cSymbolCodecArithMinLen) {
do {
const uint c = (arith_buf_ofs < m_arith_output_buf.size()) ? m_arith_output_buf[arith_buf_ofs++] : 0;
put_bits(c, 8);
m_arith_value = (m_arith_value << 8) | c;
} while ((m_arith_length <<= 8) < cSymbolCodecArithMinLen);
}
//uint x = gArithProbMulTab[sym.m_arith_prob0 >> (cSymbolCodecArithProbBits - cSymbolCodecArithProbMulBits)][m_arith_length >> (32 - cSymbolCodecArithProbMulLenSigBits)] << 16;
uint x = sym.m_arith_prob0 * (m_arith_length >> cSymbolCodecArithProbBits);
uint bit = (m_arith_value >= x);
if (bit == 0) {
m_arith_length = x;
} else {
m_arith_value -= x;
m_arith_length -= x;
}
CRNLIB_VERIFY(bit == sym.m_bits);
} else {
put_bits(sym.m_bits, sym.m_num_bits);
}
}
flush_bits();
}
//------------------------------------------------------------------------------------------------------------------
// Decoding
//------------------------------------------------------------------------------------------------------------------
bool symbol_codec::start_decoding(const uint8* pBuf, size_t buf_size, bool eof_flag, need_bytes_func_ptr pNeed_bytes_func, void* pPrivate_data) {
if (!buf_size)
return false;
m_total_model_updates = 0;
m_pDecode_buf = pBuf;
m_pDecode_buf_next = pBuf;
m_decode_buf_size = buf_size;
m_pDecode_buf_end = pBuf + buf_size;
m_pDecode_need_bytes_func = pNeed_bytes_func;
m_pDecode_private_data = pPrivate_data;
m_decode_buf_eof = eof_flag;
if (!pNeed_bytes_func) {
m_decode_buf_eof = true;
}
m_mode = cDecoding;
get_bits_init();
return true;
}
uint symbol_codec::decode_bits(uint num_bits) {
CRNLIB_ASSERT(m_mode == cDecoding);
if (!num_bits)
return 0;
if (num_bits > 16) {
uint a = get_bits(num_bits - 16);
uint b = get_bits(16);
return (a << 16) | b;
} else
return get_bits(num_bits);
}
void symbol_codec::decode_remove_bits(uint num_bits) {
CRNLIB_ASSERT(m_mode == cDecoding);
while (num_bits > 16) {
remove_bits(16);
num_bits -= 16;
}
remove_bits(num_bits);
}
uint symbol_codec::decode_peek_bits(uint num_bits) {
CRNLIB_ASSERT(m_mode == cDecoding);
CRNLIB_ASSERT(num_bits <= 25);
if (!num_bits)
return 0;
while (m_bit_count < (int)num_bits) {
uint c = 0;
if (m_pDecode_buf_next == m_pDecode_buf_end) {
if (!m_decode_buf_eof) {
m_pDecode_need_bytes_func(m_pDecode_buf_next - m_pDecode_buf, m_pDecode_private_data, m_pDecode_buf, m_decode_buf_size, m_decode_buf_eof);
m_pDecode_buf_end = m_pDecode_buf + m_decode_buf_size;
m_pDecode_buf_next = m_pDecode_buf;
if (m_pDecode_buf_next < m_pDecode_buf_end)
c = *m_pDecode_buf_next++;
}
} else
c = *m_pDecode_buf_next++;
m_bit_count += 8;
CRNLIB_ASSERT(m_bit_count <= cBitBufSize);
m_bit_buf |= (static_cast<bit_buf_t>(c) << (cBitBufSize - m_bit_count));
}
return static_cast<uint>(m_bit_buf >> (cBitBufSize - num_bits));
}
uint symbol_codec::decode(adaptive_huffman_data_model& model) {
CRNLIB_ASSERT(m_mode == cDecoding);
CRNLIB_ASSERT(!model.m_encoding);
const prefix_coding::decoder_tables* pTables = model.m_pDecode_tables;
while (m_bit_count < (cBitBufSize - 8)) {
uint c = 0;
if (m_pDecode_buf_next == m_pDecode_buf_end) {
if (!m_decode_buf_eof) {
m_pDecode_need_bytes_func(m_pDecode_buf_next - m_pDecode_buf, m_pDecode_private_data, m_pDecode_buf, m_decode_buf_size, m_decode_buf_eof);
m_pDecode_buf_end = m_pDecode_buf + m_decode_buf_size;
m_pDecode_buf_next = m_pDecode_buf;
if (m_pDecode_buf_next < m_pDecode_buf_end)
c = *m_pDecode_buf_next++;
}
} else
c = *m_pDecode_buf_next++;
m_bit_count += 8;
m_bit_buf |= (static_cast<bit_buf_t>(c) << (cBitBufSize - m_bit_count));
}
uint k = static_cast<uint>((m_bit_buf >> (cBitBufSize - 16)) + 1);
uint sym, len;
if (k <= pTables->m_table_max_code) {
uint32 t = pTables->m_lookup[m_bit_buf >> (cBitBufSize - pTables->m_table_bits)];
CRNLIB_ASSERT(t != cUINT32_MAX);
sym = t & cUINT16_MAX;
len = t >> 16;
CRNLIB_ASSERT(model.m_code_sizes[sym] == len);
} else {
len = pTables->m_decode_start_code_size;
for (;;) {
if (k <= pTables->m_max_codes[len - 1])
break;
len++;
}
int val_ptr = pTables->m_val_ptrs[len - 1] + static_cast<int>((m_bit_buf >> (cBitBufSize - len)));
if (((uint)val_ptr >= model.m_total_syms)) {
// corrupted stream, or a bug
CRNLIB_ASSERT(0);
return 0;
}
sym = pTables->m_sorted_symbol_order[val_ptr];
}
m_bit_buf <<= len;
m_bit_count -= len;
uint freq = model.m_sym_freq[sym];
freq++;
model.m_sym_freq[sym] = static_cast<uint16>(freq);
if (freq == cUINT16_MAX)
model.rescale();
if (--model.m_symbols_until_update == 0) {
m_total_model_updates++;
model.update();
}
return sym;
}
void symbol_codec::decode_set_input_buffer(const uint8* pBuf, size_t buf_size, const uint8* pBuf_next, bool eof_flag) {
CRNLIB_ASSERT(m_mode == cDecoding);
m_pDecode_buf = pBuf;
m_pDecode_buf_next = pBuf_next;
m_decode_buf_size = buf_size;
m_pDecode_buf_end = pBuf + buf_size;
if (!m_pDecode_need_bytes_func)
m_decode_buf_eof = true;
else
m_decode_buf_eof = eof_flag;
}
bool symbol_codec::decode_receive_static_huffman_data_model(static_huffman_data_model& model, static_huffman_data_model* pDeltaModel) {
CRNLIB_ASSERT(m_mode == cDecoding);
const uint total_used_syms = decode_bits(math::total_bits(prefix_coding::cMaxSupportedSyms));
if (!total_used_syms) {
model.clear();
return true;
}
model.m_code_sizes.resize(total_used_syms);
memset(&model.m_code_sizes[0], 0, sizeof(model.m_code_sizes[0]) * total_used_syms);
const uint num_codelength_codes_to_send = decode_bits(5);
if ((num_codelength_codes_to_send < 1) || (num_codelength_codes_to_send > cMaxCodelengthCodes))
return false;
static_huffman_data_model dm;
dm.m_code_sizes.resize(cMaxCodelengthCodes);
for (uint i = 0; i < num_codelength_codes_to_send; i++)
dm.m_code_sizes[g_most_probable_codelength_codes[i]] = static_cast<uint8>(decode_bits(3));
if (!dm.prepare_decoder_tables())
return false;
uint ofs = 0;
while (ofs < total_used_syms) {
const uint num_remaining = total_used_syms - ofs;
uint code = decode(dm);
if (code <= 16)
model.m_code_sizes[ofs++] = static_cast<uint8>(code);
else if (code == cSmallZeroRunCode) {
uint len = decode_bits(cSmallZeroRunExtraBits) + cMinSmallZeroRunSize;
if (len > num_remaining)
return false;
ofs += len;
} else if (code == cLargeZeroRunCode) {
uint len = decode_bits(cLargeZeroRunExtraBits) + cMinLargeZeroRunSize;
if (len > num_remaining)
return false;
ofs += len;
} else if ((code == cSmallRepeatCode) || (code == cLargeRepeatCode)) {
uint len;
if (code == cSmallRepeatCode)
len = decode_bits(cSmallNonZeroRunExtraBits) + cSmallMinNonZeroRunSize;
else
len = decode_bits(cLargeNonZeroRunExtraBits) + cLargeMinNonZeroRunSize;
if ((!ofs) || (len > num_remaining))
return false;
const uint prev = model.m_code_sizes[ofs - 1];
if (!prev)
return false;
const uint end = ofs + len;
while (ofs < end)
model.m_code_sizes[ofs++] = static_cast<uint8>(prev);
} else {
CRNLIB_ASSERT(0);
return false;
}
}
if (ofs != total_used_syms)
return false;
if ((pDeltaModel) && (pDeltaModel->get_total_syms())) {
uint n = math::minimum(pDeltaModel->m_code_sizes.size(), total_used_syms);
for (uint i = 0; i < n; i++) {
int codesize = model.m_code_sizes[i] + pDeltaModel->m_code_sizes[i];
if (codesize > 16)
codesize -= 17;
model.m_code_sizes[i] = static_cast<uint8>(codesize);
}
}
return model.prepare_decoder_tables();
}
uint symbol_codec::decode(static_huffman_data_model& model) {
CRNLIB_ASSERT(m_mode == cDecoding);
CRNLIB_ASSERT(!model.m_encoding);
const prefix_coding::decoder_tables* pTables = model.m_pDecode_tables;
while (m_bit_count < (cBitBufSize - 8)) {
uint c = 0;
if (m_pDecode_buf_next == m_pDecode_buf_end) {
if (!m_decode_buf_eof) {
m_pDecode_need_bytes_func(m_pDecode_buf_next - m_pDecode_buf, m_pDecode_private_data, m_pDecode_buf, m_decode_buf_size, m_decode_buf_eof);
m_pDecode_buf_end = m_pDecode_buf + m_decode_buf_size;
m_pDecode_buf_next = m_pDecode_buf;
if (m_pDecode_buf_next < m_pDecode_buf_end)
c = *m_pDecode_buf_next++;
}
} else
c = *m_pDecode_buf_next++;
m_bit_count += 8;
m_bit_buf |= (static_cast<bit_buf_t>(c) << (cBitBufSize - m_bit_count));
}
uint k = static_cast<uint>((m_bit_buf >> (cBitBufSize - 16)) + 1);
uint sym, len;
if (k <= pTables->m_table_max_code) {
uint32 t = pTables->m_lookup[m_bit_buf >> (cBitBufSize - pTables->m_table_bits)];
CRNLIB_ASSERT(t != cUINT32_MAX);
sym = t & cUINT16_MAX;
len = t >> 16;
CRNLIB_ASSERT(model.m_code_sizes[sym] == len);
} else {
len = pTables->m_decode_start_code_size;
for (;;) {
if (k <= pTables->m_max_codes[len - 1])
break;
len++;
}
int val_ptr = pTables->m_val_ptrs[len - 1] + static_cast<int>((m_bit_buf >> (cBitBufSize - len)));
if (((uint)val_ptr >= model.m_total_syms)) {
// corrupted stream, or a bug
CRNLIB_ASSERT(0);
return 0;
}
sym = pTables->m_sorted_symbol_order[val_ptr];
}
m_bit_buf <<= len;
m_bit_count -= len;
return sym;
}
uint symbol_codec::decode_truncated_binary(uint n) {
CRNLIB_ASSERT(n >= 2);
uint k = math::floor_log2i(n);
uint u = (1 << (k + 1)) - n;
uint i = decode_bits(k);
if (i >= u)
i = ((i << 1) | decode_bits(1)) - u;
return i;
}
uint symbol_codec::decode_golomb(uint m) {
CRNLIB_ASSERT(m > 1);
uint q = 0;
for (;;) {
uint k = decode_peek_bits(16);
uint l = utils::count_leading_zeros16((~k) & 0xFFFF);
q += l;
if (l < 16)
break;
}
decode_remove_bits(q + 1);
uint r = decode_truncated_binary(m);
return (q * m) + r;
}
uint symbol_codec::decode_rice(uint m) {
CRNLIB_ASSERT(m > 0);
uint q = 0;
for (;;) {
uint k = decode_peek_bits(16);
uint l = utils::count_leading_zeros16((~k) & 0xFFFF);
q += l;
decode_remove_bits(l);
if (l < 16)
break;
}
decode_remove_bits(1);
uint r = decode_bits(m);
return (q << m) + r;
}
uint64 symbol_codec::stop_decoding() {
CRNLIB_ASSERT(m_mode == cDecoding);
uint64 n = m_pDecode_buf_next - m_pDecode_buf;
m_mode = cNull;
return n;
}
void symbol_codec::get_bits_init() {
m_bit_buf = 0;
m_bit_count = 0;
}
uint symbol_codec::get_bits(uint num_bits) {
CRNLIB_ASSERT(num_bits <= 25);
if (!num_bits)
return 0;
while (m_bit_count < (int)num_bits) {
uint c = 0;
if (m_pDecode_buf_next == m_pDecode_buf_end) {
if (!m_decode_buf_eof) {
m_pDecode_need_bytes_func(m_pDecode_buf_next - m_pDecode_buf, m_pDecode_private_data, m_pDecode_buf, m_decode_buf_size, m_decode_buf_eof);
m_pDecode_buf_end = m_pDecode_buf + m_decode_buf_size;
m_pDecode_buf_next = m_pDecode_buf;
if (m_pDecode_buf_next < m_pDecode_buf_end)
c = *m_pDecode_buf_next++;
}
} else
c = *m_pDecode_buf_next++;
m_bit_count += 8;
CRNLIB_ASSERT(m_bit_count <= cBitBufSize);
m_bit_buf |= (static_cast<bit_buf_t>(c) << (cBitBufSize - m_bit_count));
}
uint result = static_cast<uint>(m_bit_buf >> (cBitBufSize - num_bits));
m_bit_buf <<= num_bits;
m_bit_count -= num_bits;
return result;
}
void symbol_codec::remove_bits(uint num_bits) {
CRNLIB_ASSERT(num_bits <= 25);
if (!num_bits)
return;
while (m_bit_count < (int)num_bits) {
uint c = 0;
if (m_pDecode_buf_next == m_pDecode_buf_end) {
if (!m_decode_buf_eof) {
m_pDecode_need_bytes_func(m_pDecode_buf_next - m_pDecode_buf, m_pDecode_private_data, m_pDecode_buf, m_decode_buf_size, m_decode_buf_eof);
m_pDecode_buf_end = m_pDecode_buf + m_decode_buf_size;
m_pDecode_buf_next = m_pDecode_buf;
if (m_pDecode_buf_next < m_pDecode_buf_end)
c = *m_pDecode_buf_next++;
}
} else
c = *m_pDecode_buf_next++;
m_bit_count += 8;
CRNLIB_ASSERT(m_bit_count <= cBitBufSize);
m_bit_buf |= (static_cast<bit_buf_t>(c) << (cBitBufSize - m_bit_count));
}
m_bit_buf <<= num_bits;
m_bit_count -= num_bits;
}
void symbol_codec::decode_align_to_byte() {
CRNLIB_ASSERT(m_mode == cDecoding);
if (m_bit_count & 7) {
remove_bits(m_bit_count & 7);
}
}
int symbol_codec::decode_remove_byte_from_bit_buf() {
if (m_bit_count < 8)
return -1;
int result = static_cast<int>(m_bit_buf >> (cBitBufSize - 8));
m_bit_buf <<= 8;
m_bit_count -= 8;
return result;
}
uint symbol_codec::decode(adaptive_bit_model& model, bool update_model) {
if (m_arith_length < cSymbolCodecArithMinLen) {
uint c = get_bits(8);
m_arith_value = (m_arith_value << 8) | c;
m_arith_length <<= 8;
CRNLIB_ASSERT(m_arith_length >= cSymbolCodecArithMinLen);
}
CRNLIB_ASSERT(m_arith_length >= cSymbolCodecArithMinLen);
//uint x = gArithProbMulTab[model.m_bit_0_prob >> (cSymbolCodecArithProbBits - cSymbolCodecArithProbMulBits)][m_arith_length >> (32 - cSymbolCodecArithProbMulLenSigBits)] << 16;
uint x = model.m_bit_0_prob * (m_arith_length >> cSymbolCodecArithProbBits);
uint bit = (m_arith_value >= x);
if (!bit) {
if (update_model)
model.m_bit_0_prob += ((cSymbolCodecArithProbScale - model.m_bit_0_prob) >> cSymbolCodecArithProbMoveBits);
m_arith_length = x;
} else {
if (update_model)
model.m_bit_0_prob -= (model.m_bit_0_prob >> cSymbolCodecArithProbMoveBits);
m_arith_value -= x;
m_arith_length -= x;
}
return bit;
}
uint symbol_codec::decode(adaptive_arith_data_model& model) {
uint node = 1;
do {
uint bit = decode(model.m_probs[node]);
node = (node << 1) + bit;
} while (node < model.m_total_syms);
return node - model.m_total_syms;
}
void symbol_codec::start_arith_decoding() {
CRNLIB_ASSERT(m_mode == cDecoding);
m_arith_length = cSymbolCodecArithMaxLen;
m_arith_value = 0;
if (get_bits(1)) {
m_arith_value = (get_bits(8) << 24);
m_arith_value |= (get_bits(8) << 16);
m_arith_value |= (get_bits(8) << 8);
m_arith_value |= get_bits(8);
}
}
void symbol_codec::decode_need_bytes() {
if (!m_decode_buf_eof) {
m_pDecode_need_bytes_func(m_pDecode_buf_next - m_pDecode_buf, m_pDecode_private_data, m_pDecode_buf, m_decode_buf_size, m_decode_buf_eof);
m_pDecode_buf_end = m_pDecode_buf + m_decode_buf_size;
m_pDecode_buf_next = m_pDecode_buf;
}
}
} // namespace crnlib