340 lines
14 KiB
C
340 lines
14 KiB
C
|
/*
|
||
|
Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu)
|
||
|
All rights reserved.
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without modification,
|
||
|
are permitted provided that the following conditions are met:
|
||
|
|
||
|
- Redistributions of source code must retain the above copyright notice, this list
|
||
|
of conditions and the following disclaimer.
|
||
|
|
||
|
- Redistributions in binary form must reproduce the above copyright notice, this list of
|
||
|
conditions and the following disclaimer in the documentation and/or other materials
|
||
|
provided with the distribution.
|
||
|
|
||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||
|
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||
|
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||
|
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||
|
OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// -
|
||
|
// **************************** -
|
||
|
// ARITHMETIC CODING EXAMPLES -
|
||
|
// **************************** -
|
||
|
// -
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// -
|
||
|
// Fast arithmetic coding implementation -
|
||
|
// -> 32-bit variables, 32-bit product, periodic updates, table decoding -
|
||
|
// -
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// -
|
||
|
// Version 1.00 - April 25, 2004 -
|
||
|
// -
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// -
|
||
|
// WARNING -
|
||
|
// ========= -
|
||
|
// -
|
||
|
// The only purpose of this program is to demonstrate the basic principles -
|
||
|
// of arithmetic coding. It is provided as is, without any express or -
|
||
|
// implied warranty, without even the warranty of fitness for any particular -
|
||
|
// purpose, or that the implementations are correct. -
|
||
|
// -
|
||
|
// Permission to copy and redistribute this code is hereby granted, provided -
|
||
|
// that this warning and copyright notices are not removed or altered. -
|
||
|
// -
|
||
|
// Copyright (c) 2004 by Amir Said (said@ieee.org) & -
|
||
|
// William A. Pearlman (pearlw@ecse.rpi.edu) -
|
||
|
// -
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// -
|
||
|
// A description of the arithmetic coding method used here is available in -
|
||
|
// -
|
||
|
// Lossless Compression Handbook, ed. K. Sayood -
|
||
|
// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
|
||
|
// -
|
||
|
// A. Said, Introduction to Arithetic Coding Theory and Practice -
|
||
|
// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ -
|
||
|
// -
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
|
||
|
// - - Definitions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
#ifndef O3DGC_ARITHMETIC_CODEC
|
||
|
#define O3DGC_ARITHMETIC_CODEC
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include "o3dgcCommon.h"
|
||
|
|
||
|
namespace o3dgc
|
||
|
{
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// - - Class definitions - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
class Static_Bit_Model // static model for binary data
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
Static_Bit_Model(void);
|
||
|
|
||
|
void set_probability_0(double); // set probability of symbol '0'
|
||
|
|
||
|
private: // . . . . . . . . . . . . . . . . . . . . . .
|
||
|
unsigned bit_0_prob;
|
||
|
friend class Arithmetic_Codec;
|
||
|
};
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
class Static_Data_Model // static model for general data
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
Static_Data_Model(void);
|
||
|
~Static_Data_Model(void);
|
||
|
|
||
|
unsigned model_symbols(void) { return data_symbols; }
|
||
|
|
||
|
void set_distribution(unsigned number_of_symbols,
|
||
|
const double probability[] = 0); // 0 means uniform
|
||
|
|
||
|
private: // . . . . . . . . . . . . . . . . . . . . . .
|
||
|
unsigned * distribution, * decoder_table;
|
||
|
unsigned data_symbols, last_symbol, table_size, table_shift;
|
||
|
friend class Arithmetic_Codec;
|
||
|
};
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
class Adaptive_Bit_Model // adaptive model for binary data
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
Adaptive_Bit_Model(void);
|
||
|
|
||
|
void reset(void); // reset to equiprobable model
|
||
|
|
||
|
private: // . . . . . . . . . . . . . . . . . . . . . .
|
||
|
void update(void);
|
||
|
unsigned update_cycle, bits_until_update;
|
||
|
unsigned bit_0_prob, bit_0_count, bit_count;
|
||
|
friend class Arithmetic_Codec;
|
||
|
};
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
class Adaptive_Data_Model // adaptive model for binary data
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
Adaptive_Data_Model(void);
|
||
|
Adaptive_Data_Model(unsigned number_of_symbols);
|
||
|
~Adaptive_Data_Model(void);
|
||
|
|
||
|
unsigned model_symbols(void) { return data_symbols; }
|
||
|
|
||
|
void reset(void); // reset to equiprobable model
|
||
|
void set_alphabet(unsigned number_of_symbols);
|
||
|
|
||
|
private: // . . . . . . . . . . . . . . . . . . . . . .
|
||
|
void update(bool);
|
||
|
unsigned * distribution, * symbol_count, * decoder_table;
|
||
|
unsigned total_count, update_cycle, symbols_until_update;
|
||
|
unsigned data_symbols, last_symbol, table_size, table_shift;
|
||
|
friend class Arithmetic_Codec;
|
||
|
};
|
||
|
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// - - Encoder and decoder class - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
// Class with both the arithmetic encoder and decoder. All compressed data is
|
||
|
// saved to a memory buffer
|
||
|
|
||
|
class Arithmetic_Codec
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
Arithmetic_Codec(void);
|
||
|
~Arithmetic_Codec(void);
|
||
|
Arithmetic_Codec(unsigned max_code_bytes,
|
||
|
unsigned char * user_buffer = 0); // 0 = assign new
|
||
|
|
||
|
unsigned char * buffer(void) { return code_buffer; }
|
||
|
|
||
|
void set_buffer(unsigned max_code_bytes,
|
||
|
unsigned char * user_buffer = 0); // 0 = assign new
|
||
|
|
||
|
void start_encoder(void);
|
||
|
void start_decoder(void);
|
||
|
void read_from_file(FILE * code_file); // read code data, start decoder
|
||
|
|
||
|
unsigned stop_encoder(void); // returns number of bytes used
|
||
|
unsigned write_to_file(FILE * code_file); // stop encoder, write code data
|
||
|
void stop_decoder(void);
|
||
|
|
||
|
void put_bit(unsigned bit);
|
||
|
unsigned get_bit(void);
|
||
|
|
||
|
void put_bits(unsigned data, unsigned number_of_bits);
|
||
|
unsigned get_bits(unsigned number_of_bits);
|
||
|
|
||
|
void encode(unsigned bit,
|
||
|
Static_Bit_Model &);
|
||
|
unsigned decode(Static_Bit_Model &);
|
||
|
|
||
|
void encode(unsigned data,
|
||
|
Static_Data_Model &);
|
||
|
unsigned decode(Static_Data_Model &);
|
||
|
|
||
|
void encode(unsigned bit,
|
||
|
Adaptive_Bit_Model &);
|
||
|
unsigned decode(Adaptive_Bit_Model &);
|
||
|
|
||
|
void encode(unsigned data,
|
||
|
Adaptive_Data_Model &);
|
||
|
unsigned decode(Adaptive_Data_Model &);
|
||
|
|
||
|
// This section was added by K. Mammou
|
||
|
void ExpGolombEncode(unsigned int symbol,
|
||
|
int k,
|
||
|
Static_Bit_Model & bModel0,
|
||
|
Adaptive_Bit_Model & bModel1)
|
||
|
{
|
||
|
while(1)
|
||
|
{
|
||
|
if (symbol >= (unsigned int)(1<<k))
|
||
|
{
|
||
|
encode(1, bModel1);
|
||
|
symbol = symbol - (1<<k);
|
||
|
k++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
encode(0, bModel1); // now terminated zero of unary part
|
||
|
while (k--) // next binary part
|
||
|
{
|
||
|
encode((signed short)((symbol>>k)&1), bModel0);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
unsigned ExpGolombDecode(int k,
|
||
|
Static_Bit_Model & bModel0,
|
||
|
Adaptive_Bit_Model & bModel1)
|
||
|
{
|
||
|
unsigned int l;
|
||
|
int symbol = 0;
|
||
|
int binary_symbol = 0;
|
||
|
do
|
||
|
{
|
||
|
l=decode(bModel1);
|
||
|
if (l==1)
|
||
|
{
|
||
|
symbol += (1<<k);
|
||
|
k++;
|
||
|
}
|
||
|
}
|
||
|
while (l!=0);
|
||
|
while (k--) //next binary part
|
||
|
if (decode(bModel0)==1)
|
||
|
{
|
||
|
binary_symbol |= (1<<k);
|
||
|
}
|
||
|
return (unsigned int) (symbol+binary_symbol);
|
||
|
}
|
||
|
//----------------------------------------------------------
|
||
|
|
||
|
private: // . . . . . . . . . . . . . . . . . . . . . .
|
||
|
void propagate_carry(void);
|
||
|
void renorm_enc_interval(void);
|
||
|
void renorm_dec_interval(void);
|
||
|
unsigned char * code_buffer, * new_buffer, * ac_pointer;
|
||
|
unsigned base, value, length; // arithmetic coding state
|
||
|
unsigned buffer_size, mode; // mode: 0 = undef, 1 = encoder, 2 = decoder
|
||
|
};
|
||
|
inline long DecodeIntACEGC(Arithmetic_Codec & acd,
|
||
|
Adaptive_Data_Model & mModelValues,
|
||
|
Static_Bit_Model & bModel0,
|
||
|
Adaptive_Bit_Model & bModel1,
|
||
|
const unsigned long exp_k,
|
||
|
const unsigned long M)
|
||
|
{
|
||
|
unsigned long uiValue = acd.decode(mModelValues);
|
||
|
if (uiValue == M)
|
||
|
{
|
||
|
uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
|
||
|
}
|
||
|
return UIntToInt(uiValue);
|
||
|
}
|
||
|
inline unsigned long DecodeUIntACEGC(Arithmetic_Codec & acd,
|
||
|
Adaptive_Data_Model & mModelValues,
|
||
|
Static_Bit_Model & bModel0,
|
||
|
Adaptive_Bit_Model & bModel1,
|
||
|
const unsigned long exp_k,
|
||
|
const unsigned long M)
|
||
|
{
|
||
|
unsigned long uiValue = acd.decode(mModelValues);
|
||
|
if (uiValue == M)
|
||
|
{
|
||
|
uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
|
||
|
}
|
||
|
return uiValue;
|
||
|
}
|
||
|
|
||
|
inline void EncodeIntACEGC(long predResidual,
|
||
|
Arithmetic_Codec & ace,
|
||
|
Adaptive_Data_Model & mModelValues,
|
||
|
Static_Bit_Model & bModel0,
|
||
|
Adaptive_Bit_Model & bModel1,
|
||
|
const unsigned long M)
|
||
|
{
|
||
|
unsigned long uiValue = IntToUInt(predResidual);
|
||
|
if (uiValue < M)
|
||
|
{
|
||
|
ace.encode(uiValue, mModelValues);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ace.encode(M, mModelValues);
|
||
|
ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
|
||
|
}
|
||
|
}
|
||
|
inline void EncodeUIntACEGC(long predResidual,
|
||
|
Arithmetic_Codec & ace,
|
||
|
Adaptive_Data_Model & mModelValues,
|
||
|
Static_Bit_Model & bModel0,
|
||
|
Adaptive_Bit_Model & bModel1,
|
||
|
const unsigned long M)
|
||
|
{
|
||
|
unsigned long uiValue = (unsigned long) predResidual;
|
||
|
if (uiValue < M)
|
||
|
{
|
||
|
ace.encode(uiValue, mModelValues);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ace.encode(M, mModelValues);
|
||
|
ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
#endif
|
||
|
|