1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
|
// File: lzham_symbol_codec.h
// See Copyright Notice and license at the end of include/lzham.h
#pragma once
#include "lzham_prefix_coding.h"
namespace lzham
{
class symbol_codec;
const uint cSymbolCodecArithMinLen = 0x01000000U;
const uint cSymbolCodecArithMaxLen = 0xFFFFFFFFU;
const uint cSymbolCodecArithProbBits = 11;
const uint cSymbolCodecArithProbScale = 1 << cSymbolCodecArithProbBits;
const uint cSymbolCodecArithProbHalfScale = 1 << (cSymbolCodecArithProbBits - 1);
const uint cSymbolCodecArithProbMoveBits = 5;
typedef uint64 bit_cost_t;
const uint32 cBitCostScaleShift = 24;
const uint32 cBitCostScale = (1U << cBitCostScaleShift);
const bit_cost_t cBitCostMax = cUINT64_MAX;
inline bit_cost_t convert_to_scaled_bitcost(uint bits) { LZHAM_ASSERT(bits <= 255); uint32 scaled_bits = bits << cBitCostScaleShift; return static_cast<bit_cost_t>(scaled_bits); }
extern uint32 g_prob_cost[cSymbolCodecArithProbScale];
class quasi_adaptive_huffman_data_model
{
public:
quasi_adaptive_huffman_data_model(lzham_malloc_context malloc_context = NULL, bool encoding = false, uint total_syms = 0, uint max_update_interval = 0, uint adapt_rate = 0);
quasi_adaptive_huffman_data_model(const quasi_adaptive_huffman_data_model& other);
~quasi_adaptive_huffman_data_model();
bool assign(const quasi_adaptive_huffman_data_model& rhs);
quasi_adaptive_huffman_data_model& operator= (const quasi_adaptive_huffman_data_model& rhs);
void clear();
void set_malloc_context(lzham_malloc_context malloc_context)
{
m_malloc_context = malloc_context;
m_initial_sym_freq.set_malloc_context(malloc_context);
m_sym_freq.set_malloc_context(malloc_context);
m_codes.set_malloc_context(malloc_context);
m_code_sizes.set_malloc_context(malloc_context);
}
lzham_malloc_context get_malloc_context() const { return m_malloc_context; }
bool init2(lzham_malloc_context context, bool encoding, uint total_syms, uint max_update_interval, uint adapt_rate, const uint16 *pInitial_sym_freq);
bool reset();
inline uint get_total_syms() const { return m_total_syms; }
void rescale();
void reset_update_rate();
bool update_sym(uint sym);
inline bit_cost_t get_cost(uint sym) const { return convert_to_scaled_bitcost(m_code_sizes[sym]); }
public:
lzham_malloc_context m_malloc_context;
lzham::vector<uint16> m_initial_sym_freq;
lzham::vector<uint16> m_sym_freq;
lzham::vector<uint16> m_codes;
lzham::vector<uint8> m_code_sizes;
prefix_coding::decoder_tables* m_pDecode_tables;
uint m_total_syms;
uint m_max_cycle;
uint m_update_cycle;
uint m_symbols_until_update;
uint m_total_count;
uint8 m_decoder_table_bits;
uint16 m_max_update_interval; // def=16, typical range 12-128, controls the max interval between table updates, higher=longer max interval (faster decode/lower ratio)
uint16 m_adapt_rate; // def=10, 8 or higher, scaled by 8, controls the slowing of the update update freq, higher=more rapid slowing (faster decode/lower ratio)
bool m_encoding;
bool update_tables(int force_update_cycle = -1, bool sym_freq_all_ones = false);
friend class symbol_codec;
};
class adaptive_bit_model
{
public:
inline adaptive_bit_model() { clear(); }
adaptive_bit_model(float prob0);
adaptive_bit_model(const adaptive_bit_model& other);
inline adaptive_bit_model& operator= (const adaptive_bit_model& rhs) { m_bit_0_prob = rhs.m_bit_0_prob; return *this; }
inline void clear() { m_bit_0_prob = 1U << (cSymbolCodecArithProbBits - 1); }
void set_probability_0(float prob0);
inline void 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);
LZHAM_ASSERT(m_bit_0_prob >= 1);
LZHAM_ASSERT(m_bit_0_prob < cSymbolCodecArithProbScale);
}
inline bit_cost_t get_cost(uint bit) const { return g_prob_cost[bit ? (cSymbolCodecArithProbScale - m_bit_0_prob) : m_bit_0_prob]; }
public:
uint16 m_bit_0_prob;
friend class symbol_codec;
};
#if LZHAM_CPU_HAS_64BIT_REGISTERS
#define LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER 1
#else
#define LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER 0
#endif
class symbol_codec
{
LZHAM_NO_COPY_OR_ASSIGNMENT_OP(symbol_codec);
public:
symbol_codec(lzham_malloc_context malloc_context);
void reset();
// clear() is like reset(), except it also frees all memory.
void clear();
// Encoding
bool start_encoding(uint expected_file_size);
bool encode_bits(uint bits, uint num_bits);
bool encode_arith_init();
bool encode_align_to_byte();
bool encode(uint sym, quasi_adaptive_huffman_data_model& model);
bool encode(uint bit, adaptive_bit_model& model, bool update_model = true);
inline uint encode_get_total_bits_written() const { return m_total_bits_written; }
bool stop_encoding(bool support_arith);
const lzham::vector<uint8>& get_encoding_buf() const { return m_output_buf; }
lzham::vector<uint8>& get_encoding_buf() { return m_output_buf; }
// Decoding
typedef void (*need_bytes_func_ptr)(size_t num_bytes_consumed, void *pPrivate_data, const uint8* &pBuf, size_t &buf_size, bool &eof_flag);
bool start_decoding(const uint8* pBuf, size_t buf_size, bool eof_flag = true, need_bytes_func_ptr pNeed_bytes_func = NULL, void *pPrivate_data = NULL);
inline void decode_set_input_buffer(const uint8* pBuf, size_t buf_size, const uint8* pBuf_next, bool eof_flag)
{
m_pDecode_buf = pBuf;
m_pDecode_buf_next = pBuf_next;
m_decode_buf_size = buf_size;
m_pDecode_buf_end = pBuf + buf_size;
m_decode_buf_eof = eof_flag;
}
inline uint64 decode_get_bytes_consumed() const { return m_pDecode_buf_next - m_pDecode_buf; }
inline uint64 decode_get_bits_remaining() const { return ((m_pDecode_buf_end - m_pDecode_buf_next) << 3) + m_bit_count; }
void start_arith_decoding();
uint decode_bits(uint num_bits);
uint decode_peek_bits(uint num_bits);
void decode_remove_bits(uint num_bits);
void decode_align_to_byte();
int decode_remove_byte_from_bit_buf();
uint decode(quasi_adaptive_huffman_data_model& model);
uint decode(adaptive_bit_model& model, bool update_model = true);
uint64 stop_decoding();
uint get_total_model_updates() const { return m_total_model_updates; }
public:
lzham_malloc_context m_malloc_context;
const uint8* m_pDecode_buf;
const uint8* m_pDecode_buf_next;
const uint8* m_pDecode_buf_end;
size_t m_decode_buf_size;
bool m_decode_buf_eof;
need_bytes_func_ptr m_pDecode_need_bytes_func;
void* m_pDecode_private_data;
#if LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER
typedef uint64 bit_buf_t;
enum { cBitBufSize = 64 };
#else
typedef uint32 bit_buf_t;
enum { cBitBufSize = 32 };
#endif
bit_buf_t m_bit_buf;
int m_bit_count;
uint m_total_model_updates;
lzham::vector<uint8> m_output_buf;
lzham::vector<uint8> m_arith_output_buf;
struct output_symbol
{
uint m_bits;
enum
{
cArithSym = -1,
cAlignToByteSym = -2,
cArithInit = -3
};
int16 m_num_bits;
uint16 m_arith_prob0;
};
lzham::vector<output_symbol> m_output_syms;
uint m_total_bits_written;
uint m_arith_base;
uint m_arith_value;
uint m_arith_length;
uint m_arith_total_bits;
quasi_adaptive_huffman_data_model* m_pSaved_huff_model;
void* m_pSaved_model;
uint m_saved_node_index;
bool put_bits_init(uint expected_size);
bool record_put_bits(uint bits, uint num_bits);
void arith_propagate_carry();
bool arith_renorm_enc_interval();
void arith_start_encoding();
bool arith_stop_encoding();
bool put_bits(uint bits, uint num_bits);
bool put_bits_align_to_byte();
bool flush_bits();
bool assemble_output_buf();
uint get_bits(uint num_bits);
void remove_bits(uint num_bits);
void decode_need_bytes();
enum
{
cNull,
cEncoding,
cDecoding
} m_mode;
};
// Optional macros for faster decompression. These macros implement the symbol_codec class's decode functionality.
// This is hard to debug (and just plain ugly), but using these macros eliminate function calls, and they place the most important
// member variables on the stack so they're hopefully put in registers (avoiding horrible load hit stores on some CPU's).
// The user must define the LZHAM_DECODE_NEEDS_BYTES macro, which is invoked when the decode buffer is exhausted.
#define LZHAM_SYMBOL_CODEC_DECODE_DECLARE(codec) \
uint arith_value = 0; \
uint arith_length = 0; \
symbol_codec::bit_buf_t bit_buf = 0; \
int bit_count = 0; \
const uint8* pDecode_buf_next = NULL;
#define LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
arith_value = codec.m_arith_value; \
arith_length = codec.m_arith_length; \
bit_buf = codec.m_bit_buf; \
bit_count = codec.m_bit_count; \
pDecode_buf_next = codec.m_pDecode_buf_next;
#define LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
codec.m_arith_value = arith_value; \
codec.m_arith_length = arith_length; \
codec.m_bit_buf = bit_buf; \
codec.m_bit_count = bit_count; \
codec.m_pDecode_buf_next = pDecode_buf_next;
// The user must declare the LZHAM_DECODE_NEEDS_BYTES macro.
#define LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, result, num_bits) \
{ \
while (LZHAM_BUILTIN_EXPECT(bit_count < (int)(num_bits), 0)) \
{ \
uint r; \
if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next == codec.m_pDecode_buf_end, 0)) \
{ \
if (LZHAM_BUILTIN_EXPECT(!codec.m_decode_buf_eof, 1)) \
{ \
LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
LZHAM_DECODE_NEEDS_BYTES \
LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
} \
r = 0; \
if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next < codec.m_pDecode_buf_end, 1)) r = *pDecode_buf_next++; \
} \
else \
r = *pDecode_buf_next++; \
bit_count += 8; \
bit_buf |= (static_cast<symbol_codec::bit_buf_t>(r) << (symbol_codec::cBitBufSize - bit_count)); \
} \
result = (num_bits) ? static_cast<uint>(bit_buf >> (symbol_codec::cBitBufSize - (num_bits))) : 0; \
bit_buf <<= (num_bits); \
bit_count -= (num_bits); \
}
#define LZHAM_SYMBOL_CODEC_DECODE_ARITH_BIT(codec, result, model) \
{ \
adaptive_bit_model *pModel; \
pModel = &model; \
while (LZHAM_BUILTIN_EXPECT(arith_length < cSymbolCodecArithMinLen, 0)) \
{ \
uint c; codec.m_pSaved_model = pModel; \
LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, c, 8); \
pModel = static_cast<adaptive_bit_model*>(codec.m_pSaved_model); \
arith_value = (arith_value << 8) | c; \
arith_length <<= 8; \
} \
uint x = pModel->m_bit_0_prob * (arith_length >> cSymbolCodecArithProbBits); \
result = (arith_value >= x); \
if (!result) \
{ \
pModel->m_bit_0_prob += ((cSymbolCodecArithProbScale - pModel->m_bit_0_prob) >> cSymbolCodecArithProbMoveBits); \
arith_length = x; \
} \
else \
{ \
pModel->m_bit_0_prob -= (pModel->m_bit_0_prob >> cSymbolCodecArithProbMoveBits); \
arith_value -= x; \
arith_length -= x; \
} \
}
#if LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER
#define LZHAM_SYMBOL_CODEC_DECODE_ADAPTIVE_HUFFMAN(codec, result, model) \
{ \
quasi_adaptive_huffman_data_model* pModel; const prefix_coding::decoder_tables* pTables; \
pModel = &model; pTables = model.m_pDecode_tables; \
if (LZHAM_BUILTIN_EXPECT(bit_count < 24, 0)) \
{ \
uint c; \
pDecode_buf_next += sizeof(uint32); \
if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next >= codec.m_pDecode_buf_end, 0)) \
{ \
pDecode_buf_next -= sizeof(uint32); \
while (bit_count < 24) \
{ \
if (!codec.m_decode_buf_eof) \
{ \
codec.m_pSaved_huff_model = pModel; \
LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
LZHAM_DECODE_NEEDS_BYTES \
LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
pModel = codec.m_pSaved_huff_model; pTables = pModel->m_pDecode_tables; \
} \
c = 0; if (pDecode_buf_next < codec.m_pDecode_buf_end) c = *pDecode_buf_next++; \
bit_count += 8; \
bit_buf |= (static_cast<symbol_codec::bit_buf_t>(c) << (symbol_codec::cBitBufSize - bit_count)); \
} \
} \
else \
{ \
c = LZHAM_READ_BIG_ENDIAN_UINT32(pDecode_buf_next - sizeof(uint32)); \
bit_count += 32; \
bit_buf |= (static_cast<symbol_codec::bit_buf_t>(c) << (symbol_codec::cBitBufSize - bit_count)); \
} \
} \
uint k = static_cast<uint>((bit_buf >> (symbol_codec::cBitBufSize - 16)) + 1); \
uint len; \
if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_table_max_code, 1)) \
{ \
uint32 t = pTables->m_lookup[bit_buf >> (symbol_codec::cBitBufSize - pTables->m_table_bits)]; \
result = t & cUINT16_MAX; \
len = t >> 16; \
} \
else \
{ \
len = pTables->m_decode_start_code_size; \
for ( ; ; ) \
{ \
if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_max_codes[len - 1], 0)) \
break; \
len++; \
} \
int val_ptr = pTables->m_val_ptrs[len - 1] + static_cast<int>(bit_buf >> (symbol_codec::cBitBufSize - len)); \
if (((uint)val_ptr >= pModel->m_total_syms)) val_ptr = 0; \
result = pTables->m_sorted_symbol_order[val_ptr]; \
} \
bit_buf <<= len; \
bit_count -= len; \
uint freq = pModel->m_sym_freq[result]; \
freq++; \
pModel->m_sym_freq[result] = static_cast<uint16>(freq); \
LZHAM_ASSERT(freq <= cUINT16_MAX); \
if (LZHAM_BUILTIN_EXPECT(--pModel->m_symbols_until_update == 0, 0)) \
{ \
pModel->update_tables(); \
} \
}
#else
#define LZHAM_SYMBOL_CODEC_DECODE_ADAPTIVE_HUFFMAN(codec, result, model) \
{ \
quasi_adaptive_huffman_data_model* pModel; const prefix_coding::decoder_tables* pTables; \
pModel = &model; pTables = model.m_pDecode_tables; \
while (LZHAM_BUILTIN_EXPECT(bit_count < (symbol_codec::cBitBufSize - 8), 1)) \
{ \
uint c; \
if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next == codec.m_pDecode_buf_end, 0)) \
{ \
if (LZHAM_BUILTIN_EXPECT(!codec.m_decode_buf_eof, 1)) \
{ \
codec.m_pSaved_huff_model = pModel; \
LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
LZHAM_DECODE_NEEDS_BYTES \
LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
pModel = codec.m_pSaved_huff_model; pTables = pModel->m_pDecode_tables; \
} \
c = 0; if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next < codec.m_pDecode_buf_end, 1)) c = *pDecode_buf_next++; \
} \
else \
c = *pDecode_buf_next++; \
bit_count += 8; \
bit_buf |= (static_cast<symbol_codec::bit_buf_t>(c) << (symbol_codec::cBitBufSize - bit_count)); \
} \
uint k = static_cast<uint>((bit_buf >> (symbol_codec::cBitBufSize - 16)) + 1); \
uint len; \
if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_table_max_code, 1)) \
{ \
uint32 t = pTables->m_lookup[bit_buf >> (symbol_codec::cBitBufSize - pTables->m_table_bits)]; \
result = t & cUINT16_MAX; \
len = t >> 16; \
} \
else \
{ \
len = pTables->m_decode_start_code_size; \
for ( ; ; ) \
{ \
if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_max_codes[len - 1], 0)) \
break; \
len++; \
} \
int val_ptr = pTables->m_val_ptrs[len - 1] + static_cast<int>(bit_buf >> (symbol_codec::cBitBufSize - len)); \
if (LZHAM_BUILTIN_EXPECT(((uint)val_ptr >= pModel->m_total_syms), 0)) val_ptr = 0; \
result = pTables->m_sorted_symbol_order[val_ptr]; \
} \
bit_buf <<= len; \
bit_count -= len; \
uint freq = pModel->m_sym_freq[result]; \
freq++; \
pModel->m_sym_freq[result] = static_cast<uint16>(freq); \
LZHAM_ASSERT(freq <= cUINT16_MAX); \
if (LZHAM_BUILTIN_EXPECT(--pModel->m_symbols_until_update == 0, 0)) \
{ \
pModel->update_tables(); \
} \
}
#endif
#define LZHAM_SYMBOL_CODEC_DECODE_ALIGN_TO_BYTE(codec) if (bit_count & 7) { int dummy_result; LZHAM_NOTE_UNUSED(dummy_result); LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, dummy_result, bit_count & 7); }
#define LZHAM_SYMBOL_CODEC_DECODE_REMOVE_BYTE_FROM_BIT_BUF(codec, result) \
{ \
result = -1; \
if (bit_count >= 8) \
{ \
result = static_cast<int>(bit_buf >> (symbol_codec::cBitBufSize - 8)); \
bit_buf <<= 8; \
bit_count -= 8; \
} \
}
#define LZHAM_SYMBOL_CODEC_DECODE_ARITH_START(codec) \
{ \
for ( arith_value = 0, arith_length = 0; arith_length < 4; ++arith_length ) \
{ \
uint val; LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, val, 8); \
arith_value = (arith_value << 8) | val; \
} \
arith_length = cSymbolCodecArithMaxLen; \
}
} // namespace lzham
|