1、算术编码原理
ELisa算是编码请看面链接
2、MQ编码器有限精度编码实现
先看一个二进制小数的表示方法,比如m = 0.000101,那么这里十进制m=2^-32-3(5),这里前一个3对应小数点后面到有效位数的三个0,后面的3指的是101的位数,三位,5就是101的十进制表示,自己可以算一下。
3、源码细节
3.1switch开关问题
在源码中,我们并没有看到switch数组,那么这个LPS与MPS相互切换的开关在哪里呢?
ok,在源码哪个数组中,上下文状态共有0~46共47中,然后切换0/1状态每个两种,这也是为什么组是47*2,也就是说他们对应着切换完的状态,不信自己去看,相邻两个相同
static const opj_mqc_state_t mqc_states[47 * 2] = {
{0x5601, 0, &mqc_states[2], &mqc_states[3]},
{0x5601, 1, &mqc_states[3], &mqc_states[2]},
{0x3401, 0, &mqc_states[4], &mqc_states[12]},
{0x3401, 1, &mqc_states[5], &mqc_states[13]},
{0x1801, 0, &mqc_states[6], &mqc_states[18]},
{0x1801, 1, &mqc_states[7], &mqc_states[19]},
{0x0ac1, 0, &mqc_states[8], &mqc_states[24]},
{0x0ac1, 1, &mqc_states[9], &mqc_states[25]},
{0x0521, 0, &mqc_states[10], &mqc_states[58]},
{0x0521, 1, &mqc_states[11], &mqc_states[59]},
{0x0221, 0, &mqc_states[76], &mqc_states[66]},
.....
{0x5601, 0, &mqc_states[92], &mqc_states[92]},
{0x5601, 1, &mqc_states[93], &mqc_states[93]},
};
3.2比特输出
下面是归一化区间A的过程,源码如下所示,首先这里保存的是bp即buffer-pointer指向的是被压缩的数据,在文献中常看到后面进位的影响,没错这里bp由于没有更新,所以是上次的值,即从c的移入B寄存器的值,如果后面的数据有进位,我们需要对当前这个bp指向的数据进行+1处理,但是当+1>0xff时候我们往后更改bp指针非常麻烦,所以这里,位填充,什么意思呢?就是如果我上一次输出的是0xff,那么当前如果有进位,那么我就把这个进位以及Cb的前七个bit一起输送给下个bp++所在的指针,如果当前不是0xff,那么如果有进位,我们只需要在上一次输出的这个加上1就好了,但是问题来了,加1之后数据变成0xff,我怎么判断有没有进位了,这里把C的Cc清0,然后把Cc和Cb的前七个字节输出给了下一个bp,此时ct也需要变化,如果输出了最高位,也就是说Cb还有一位没有输出,那么此时Ct为7,否则为8
static void opj_mqc_byteout(opj_mqc_t *mqc)
{
/* bp is initialized to start - 1 in opj_mqc_init_enc() */
/* but this is safe, see opj_tcd_code_block_enc_allocate_data() */
assert(mqc->bp >= mqc->start - 1);
if (*mqc->bp == 0xff) {//位填充的过程
mqc->bp++;
*mqc->bp = (OPJ_BYTE)(mqc->c >> 20);
mqc->c &= 0xfffff;
mqc->ct = 7;
} else {
if ((mqc->c & 0x8000000) == 0) {//判断一下当前有没有进位
mqc->bp++;
*mqc->bp = (OPJ_BYTE)(mqc->c >> 19);
mqc->c &= 0x7ffff;
mqc->ct = 8;
} else {//当前有进位
(*mqc->bp)++;//直接对它进行加就可以了,因为进位,这里的bp应为还没有更新所以还是上一次的值
if (*mqc->bp == 0xff) {//在判断位填充,由于已经加了,所以讲最高位取消变为0,到那时此时由于编程了0xff,所以需要
mqc->c &= 0x7ffffff;
mqc->bp++;
*mqc->bp = (OPJ_BYTE)(mqc->c >> 20);
mqc->c &= 0xfffff;
mqc->ct = 7;
} else {//当前小于0xff,直接正常输出
mqc->bp++;
*mqc->bp = (OPJ_BYTE)(mqc->c >> 19);
mqc->c &= 0x7ffff;
mqc->ct = 8;
}
}
}
}