A律十三折线法G711编解码介绍
A律十三折线法G711编解码介绍
简介
G711国际电信联盟ITU-T定制出来的一套语音压缩标准,主要用于对PCM音频数据编码,将PCM16bit数据压缩为为8Bit,它是主流的波形音频编码器,相当于只在帧内压缩,不会从帧间之间来考虑压缩,输出码率通常大于32kbps,所以推荐输入信号码率为64kbps,8Khz和S16的采样格式,压缩比为1:2;
G711有两套编码标准A-law用于13bit压缩为8bit,u-law则是用于15bit压缩为8bit;前者主要用于北美和中国地区,后者则用于欧美和日本地区;
数学原理
简单来说,G711可以将16Bit数据压缩为8Bit数据。编码有两种A-law和u-law,A-law编码针对计算机做了设计处理,将13Bit压缩为8Bit,而u-law则是15Bit数据压缩;国内通用前者,所以我们以A-law为例讲解,它的函数公式:
A=87.6时,函数图像接近原点,函数图像如下:
该函数图中,X表示输入信号,Y表示输出信号,且均归一化到(-1, +1)区间;将x轴(0,1)非均匀量化为为8段1/2、1/4、… 1/64、1/128最终到原点0,共8段;同理每段对应到Y轴上也有8段,并且x负轴也分为这相同的8段,在原点(0,0)处,-1/64到+1/64是实质是相同的斜率,可归纳一个段,加上剩余的12段,也就是十三段,经过十三折线后的函数图像不再像上图的曲线,而是一段段的直线连接,折线图逼近A-law曲线图,故称十三折线法;并且十三段折线对应不同的斜率,在值较小时,曲线斜率近似于折线,精度较高,而值较大时,则曲线斜率与折线相差较大,精度较低
在以上基础上,我们将每一个(如1-1/2、1/2-1/4)大段称为“段落”,在每个段落内部实现均分16分,这样在X轴上(-1,+1)就有16个段落 * 16个均分 = 256个量级;对应到Y轴上也是256个量级,这样我们就将输入信号编码离散化到256个量级范围,刚好是8Bit,也就是编码后的值范围在256量级,也就是8Bit;而输入端X,我们段落之间非均匀化划分,段内16分均匀划分,这种均匀-非均匀量化范围可以0~2048(12bit)的范围,加上还有负数的情况(1bit极性),所以我们输入信号可以对13bit的数据进行编码,按照这种原理进行量化的表格如下:
量化范围 | 归一化 | 段落码(3bit) | 权重值 |
---|---|---|---|
0~16 | 0~1/128 | 0 0 0 | 8 4 2 1 |
16~32 | 1/128~1/64 | 0 0 1 | 8 4 2 1 |
32-64 | 1/64~1/32 | 0 1 0 | 16 8 4 2 |
64~128 | 1/32~1/16 | 0 1 1 | 32 16 8 4 |
128~256 | 1/16~1/8 | 1 0 0 | 64 32 16 8 |
256~512 | 1/8~1/4 | 1 0 1 | 128 64 32 16 |
512~1024 | 1/4~1/2 | 1 1 0 | 256 128 64 32 |
1024~2048 | 1/2~1 | 1 1 1 | 512 256 128 64 |
总段落实质是16个段落,8个正8个负,负数情况下转为正进行查表,同时记录正负极性
而段内码是均匀划分,表格如何:
量化范围 | 段内码(4bit) |
---|---|
0 | 0x0 |
1 | 0x1 |
2 | 0x2 |
… | … |
15 | 0xf |
拥有上面两张表后,我们就可以实现对输入信号进行编码压缩了,上面段落码+段内码一共才7bit,还差一位bit,这个就是信号的极性,正负了;
例如,输入信号2000,请问输出编码是多少?
- 确定段落码
2000在1024~2048段,所以段落码是1 1 1 - 确定段内码
2000 - 1024 = 976,1024~2048段内权重值为512 256 128 64,也就是512x + 256y+128z + 64w趋近于976,最终x=1,y=1,z=1,w=1; - 极性取反2000的符号位是0,所以极性为1
最终2000的编码值为1 1 1 1 1 1 1 1 = 0xff
计算机实现
以上是十三折线法原理,但是转化到计算机上来还是有区别的,例如我们一般存储数据类型都是8的倍数类型存储,如short类型就是16bit,但是十三折线是针对13bit的数据压缩,这个时候就需要自行处理,移除低位3bit或者高位3bit,根据自己的需求处理;并且计算机处理做了特殊的改动,以下表为准:
- Linear Input code 代表输入的十三bit信号值,s是符号位0…1代表序号位,abcd代表强度位,x是会移除的bit
- Compressed code是经过压缩编码后的数据,s取反,0…1表示输入的序号位,高位第一个1的位置,abcd则是输入保留下来的
- Linear output code是逆过程,解码后的数据,s恢复,abcd恢复,输入x则只会添1做补偿,其他为0,这块也就是误差值存在
所以,按照上述表格,进行编码的步骤:
- 获取符号位
- 确定序号位的第一个高位1的位置,并确定序号编码
- 获取强度为abcd,也就是序号位后紧跟的4bit
- 最后还需要进行异或处理
最后,贴源码,网上有很多,我也是参考别人的,因为已经写得很好了,没必要自己在去重新实现:
#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
#define QUANT_MASK (0xf) /* Quantization field mask. */
#define NSEGS (8) /* Number of A-law segments. */
#define SEG_SHIFT (4) /* Left shift for segment number. */
#define SEG_MASK (0x70) /* Segment field mask. */
#define BIAS (0x84) /* Bias for linear code. */
#define CLIP 8159#define G711_A_LAW (0)
#define G711_MU_LAW (1)
#define DATA_LEN (16)
确定序号位的顺序index
static short seg_aend[8] = { 0x1F, 0x3F, 0x7F, 0xFF,0x1FF, 0x3FF, 0x7FF, 0xFFF
};
编码函数
unsigned char linear2alaw(int pcm_val)
{int mask;int seg; unsigned char aval;移除低位3bitpcm_val = pcm_val >> 3;根据值正负确定mask掩码if (pcm_val >= 0) {mask = 0xD5;/* sign (7th) bit = 1 */} else {mask = 0x55;/* sign bit = 0 */因为十三折线输入信号正负范围都是一样的,但是有符号的类型如char是-128~+127负数是多一位,这里减一刚好和正数对应,并且pcm_val变为正值了,对应去编码pcm_val = -pcm_val - 1;}查找序号位indexseg = search(pcm_val, seg_aend, 8);编码超过最大值,去范围内最大值0x7fif (seg >= 8)/* out of range, return maximum value. */return (unsigned char) (0x7F ^ mask);else { aval = (unsigned char) seg << SEG_SHIFT;为什么要分两种情况?seg为2说明序号位位于第一位,再他后面只有5个bit了,只能移动一位if (seg < 2) aval |= (pcm_val >> 1) & QUANT_MASK;seg大于2情况右移seg个bit,只保留其后4位强度位即可else aval |= (pcm_val >> seg) & QUANT_MASK;异或处理返回 return (aval ^ mask);}
}
解码过程
int alaw2linear(unsigned char a_val)
{int t;int seg;得到偶数位异或后的值a_val ^= 0x55;获取强度位4bit,并且左移动4位,强度位也已经在编码前的位置了t = (a_val & QUANT_MASK) << 4;获取序号位,也就是符号位后面第几位是1seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;switch (seg) {符号位全为0的情况,说明编码之前的值很小,而t是强度位保留下来了,就补偿加8,8刚好是一个字节低4位的最大值,当做补偿case 0:t += 8;break;符号位为1,说明7位序号位刚好最后一位是1 也就是0x0100 中间强度位刚好4个字节为t 低4位补偿8 case 1:printf("i'm here");t += 0x108;break;default:其他符号位则以序号位为1的情况进行左移动,将序号位移动到正确的位置上去t += 0x108;t <<= seg - 1;}根据符号位确定返回正负值return ((a_val & SIGN_BIT) ? t : -t);
}
以上就是A-law的算法原理以及实现过程,u-law是15折线法,和A-law原理差不多,感兴趣的可以自行去研究,这里就不再阐述了!
参考文献
关于二进制的基础知识
PCM的A律13折线编码介绍
通信原理之13折线