📄 arithenc.c
字号:
/*****************************************************************************
// 程序: ebcot 编码
// 版本: V0.0
// 作者: 胡运平
// 最后修改时间 : 30, 6, 2005
// 功能描述:
Context variables made global, rather than access via pointers.
Manually inlined the CodeMPS and CodeLPS functions.
Implements mq 编码解码,实现MQ编码解码所需要的参数
****************************************************************************/
#include <stdio.h>
#include"mq_code.h"
// Set this to inline to make all internal functions inline.
#define inline
typedef struct
//上下文状态的相关信息
{
unsigned char I; //values in the range 0..46
unsigned char MPS; //MPS(either 0 or 1
} ArithEncContext;
//算术编码器所需要的状态信息
static long int C; //下限寄存器
static long int A; //间隔长度寄存器
static long int CT; //向下计数器
static unsigned char B; // The byte that is currently being assembled
static int firstByte;
//1 if the current byte is the first output byte, otherwise 0
//static int L;//代表到当前为止所产生的编码字节数
//static uint8 T;//临时字节缓冲器
//用 static来声明一个变量的作用有两个,一是对局部变量用static声明,则为该变量分配
//的空间在整个程序执行期间始终存在。二是全局变量用static声明,则该变量的作用域只限于
//本文件模块。
// The array of allowable context states
#define MAXCONTEXT 18
static ArithEncContext contexts[MAXCONTEXT+1];//19个(I,MPS)
// Special context labels
#define RUNLENGTH_CX 17
#define UNIFORM_CX 18
/*****************************************************************************
Define these inputs to have different data types
******************************************************************************/
static long int Qe[47] =
{//Qe值的十六进制表示
0x5601UL, 0x3401UL, 0x1801UL, 0x0ac1UL, 0x0521UL, 0x0221UL, 0x5601UL,
0x5401UL, 0x4801UL, 0x3801UL, 0x3001UL, 0x2401UL, 0x1c01UL, 0x1601UL,
0x5601UL, 0x5401UL, 0x5101UL, 0x4801UL, 0x3801UL, 0x3401UL, 0x3001UL,
0x2801UL, 0x2401UL, 0x2201UL, 0x1c01UL, 0x1801UL, 0x1601UL, 0x1401UL,
0x1201UL, 0x1101UL, 0x0ac1UL, 0x09c1UL, 0x08a1UL, 0x0521UL, 0x0441UL,
0x02a1UL, 0x0221UL, 0x0141UL, 0x0111UL, 0x0085UL, 0x0049UL, 0x0025UL,
0x0015UL, 0x0009UL, 0x0005UL, 0x0001UL, 0x5601UL
};
static unsigned char SWITCH[47] =
{
1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
};
static unsigned char NMPS[47] =
{
1 , 2 , 3 , 4 , 5 , 38 ,
7 , 8 , 9 , 10 , 11 , 12 , 13 , 29 ,
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 , 45 ,
46
};
static unsigned char NLPS[47] =
{
1 , 6 , 9 , 12 , 29 , 33 ,
6 , 14 , 14 , 14 , 17 , 18 , 20 , 21 ,
14 , 14 , 15 , 16 , 17 , 18 , 19 , 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 ,
46
};
/******************************************************************************
//初始化算术编码器
******************************************************************************/
void ArithEncInit()
{
int i;
A = 0x8000u;
C = 0;
B = 0; // Assume that the byte prior to starting is 0
CT = 12;//表示在寄存器中有三个隔离比特,他们需要在达到字节被移开的区域之前被填入
firstByte = 1;//1 if the current byte is the first output byte
//初始化所有的上下文状态
for (i = 0; i <= MAXCONTEXT; i++)//18
{
contexts[i].I = 0;
contexts[i].MPS = 0;
}
contexts[UNIFORM_CX].I = 46;//18
contexts[RUNLENGTH_CX].I = 3;//17
contexts[0].I = 4;//0全0邻点
}
/*****************************************************************************
//输入字节
*****************************************************************************/
static inline void ByteOutRight(void)
{
if (!firstByte)//不是第一个输出的字节标志
TransmitByte(B);
else//the current byte is the first output byte
firstByte = 0;
B = (unsigned char)((C >> 20) & 0xFF);//B是C寄存器中的8个b
C = C & 0xFFFFF;
CT = 7;
}
/*****************************************************************************
//输入字节
*****************************************************************************/
static inline void ByteOutLeft(void)
{
if (!firstByte)
TransmitByte(B);
else//the current byte is the first output byte
firstByte = 0;
B = (unsigned char)((C >> 19) & 0xFF);
C = C & 0x7FFFF;
CT = 8;
}
/*****************************************************************************
//输入字节Write out bytes, allowing for 0xFF stuffing.
*****************************************************************************/
static inline void ByteOut(void)
{
/* This test sequence might speed up process */
if (B != 0xFF)
{
if (C < 0x8000000)
ByteOutLeft();
else
{
B += 1;
if (B != 0xFF)
ByteOutLeft();
else
{
C = C & 0x7FFFFFF;
ByteOutRight();
}
}
}
else
ByteOutRight();
}
/*****************************************************************************
编码中的重新归一化直到概率区间A的大小超过0.75
*****************************************************************************/
static inline void Renorme(void)
{
do
{//Check that there will be no overflow with these shifts
A <<= 1;
C <<= 1;
CT -= 1;
if (CT == 0)
ByteOut();
}while (A <= 0x8000);//while((A && 0x8000)==0)
}
/*****************************************************************************
//Encode a bit using the given context.Output bits will be written to the file
given to ArithEncInit().
param: D - The bit to encode, either 0 or 1.
param: CX - The number of the context to use.
*****************************************************************************/
void ArithEncEncode(unsigned char D,unsigned char CX)
{
ArithEncContext *pCX;//指向ArithEncContext的指针
unsigned char I;
long int QeI;
unsigned char MPS;
pCX = &(contexts[CX]);
//Put the current context into globals, and write them back later
I = pCX->I;//索引号0--46
MPS = pCX->MPS;//二进制数据。0 1
QeI = Qe[I];//概率估计值
if (pCX->MPS == D)
{/* CodeMPS */
A -= QeI;
if (A >= 0x8000u)//if ((A & 0x8000) != 0)
{
C += QeI;
}
else//概率区间比下限值0.75小的话
{
if (A >= QeI)
C += QeI;
else
A = QeI;
I = NMPS[I];
Renorme();
}
}
else
{/* CodeLPS */
A -= QeI;
if (A >= QeI)
A = QeI;
else
C += QeI;
if (SWITCH[I])
MPS = 1 - MPS;
I = NLPS[I];
Renorme();
}
pCX->I = I;
pCX->MPS = MPS;
}
/*****************************************************************************
//Flush the output of the arithmetic encoding process.
This must be called once all of the data bits have been sent through the
encoder.
*****************************************************************************/
void ArithEncFlush(void)
{
//设置寄存器C的最后几位比特
long int tempC;
tempC = C + A;
C |= 0xFFFF;
if (C >= tempC)
C -= 0x8000;
//完成
C <<= CT;
ByteOut();
C <<= CT;
ByteOut();
if (B != 0xFF)
TransmitByte(B);
ArithEncInit();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -