最近看語音編碼,發現網上大都只給出了G711的代碼,確沒有介紹原理,儘管很簡單,但直接看代碼也是有點摸不着。下面找到了原理進行簡要的敘述,並給出了在網上找到的代碼。
1.介紹:
G.711
也稱爲PCM(脈衝編碼調製),是國際電信聯盟訂定出來的一套語音壓縮標準,主要用於電話。它主要用脈衝編碼調製對音頻採樣,採樣率爲8k每秒。它利用一個
64Kbps 未壓縮通道傳輸語音訊號。起壓縮率爲1:2,即把16位數據壓縮成8位。G.711是主流的波形聲音編解碼器。
G.711 標準下主要有兩種壓縮算法。一種是µ-law algorithm (又稱often u-law, ulaw, mu-law),主要運用於北美和日本;另一種是A-law algorithm,主要運用於歐洲和世界其他地區。其中,後者是特別設計用來方便計算機處理的。這兩種算法都使用一個採樣率爲8kHz的輸入來創建64Kbps的數字輸出。G.711採用一種稱爲分組丟失隱藏(PLC)的技術來減少丟包帶來的實際影響。有效的信號帶寬在靜默期間通過語音活動檢測(VAD)這一過程被減小。
2.原理概述:
G.711編碼方式將14bits(採用16bits採樣與存儲)的PCM信號編碼成8bits的樣本進行傳輸。
原理:取影響較爲重要的位編碼成8位(保留重要位),比如下面的數據,前N較具有影響力,(以下2組數據,N=5)
0000 0001 1111 1111 (511)
0000 0001 1111 0000 (496)
0001 1111 1111 1111 (8191)
0001 1111 0000 0000 (7936)
3.alaw編碼規則:
取影響最大的5位(1位爲強度位,4位樣本位),sign爲樣本的符號位,同時編碼後的數據逢偶數爲取補數。即^0xD5。編碼表如下,s位符號位正數時s=1。
比如pcm=3210(0000 1100 1000 1010)2
1. int sign = pcm & 0x8000) >> 8;
S=1;
2. 取強度位
0 0001 10010001010
Xs = 100
3. 取高位樣本
0 0001 10010001010
wxyz = 1001
4. 結合以上數字
s xxx wxyz
1 100 1001
5. 逢偶位數取補數
1 1001001
1 0011100
4.ULaw編碼規則:
1.取得範圍值,得到8-bit基本值
2.取得間隔數值size。如圖所示:
3.取得區間基本值rb(ex2015)
4.算出與區間基本值rb的距離d d = rb - sample
5.依據間距大小size,算出平移量s = d / size
6.與8-bit基本值相加output = b + s
7903 |
8159 4319 |
4063 |
4063 2143 |
2015 |
2015 1055 |
991 |
991 511 |
479 |
479 239 |
223 |
223 103 |
95 |
95 35 |
31 |
31 3 |
0 |
1 0 |
範例 : 2345 => 0x9D
1.取得範圍值
range => 4063~2015
1-1.得到8-bit基本值
b = 0x90
2.取得間隔數值
size = 128
3.取得區間基本值
4063 |
4063 2143 |
rb = 4063
4.算出與區間基本值rb的距離d
d = rb – sample = 4063 – 2345 = 1718
5.依據間距大小size,算出平移量
s = d / size = 1718 / 128 = 13.42… => 13
6.與8-bit基本值相加
output = b + s = 0x90 + 13 = 9D
5.代碼
//編碼
int CG711Decoder::G711_EnCode(unsigned char* pCodecBits, const char* pBuffer, int nBufferSize)
{
short* buffer = (short*)pBuffer;
for(int i=0; i<nBufferSize/2; i++)
{
pCodecBits[i] = encode(buffer[i]);
}
return nBufferSize/2;
}
//解碼
int CG711Decoder::G711_Decode(char* pRawData, const unsigned char* pBuffer, int nBufferSize)
{
short *out_data = (short*)pRawData;
for(int i=0; i<nBufferSize; i++)
{
out_data[i] = decode(pBuffer[i]);
}
return nBufferSize*2;
}
#define MAX (32635)
unsigned char CG711Decoder::encode(short pcm)
{
int sign = (pcm & 0x8000) >> 8;
if (sign != 0)
pcm = -pcm; //最高位,符號位
if (pcm > MAX) pcm = MAX; //max=32635
int exponent = 7;
int expMask;
for (expMask = 0x4000; (pcm & expMask) == 0 ///bit14->14-7,找到高字節中第一個不爲0的位
&& exponent>0; exponent--, expMask >>= 1) { }
int mantissa = (pcm >> ((exponent == 0) ? 4 : (exponent + 3))) & 0x0f;
unsigned char alaw = (unsigned char)(sign | exponent << 4 | mantissa);
return (unsigned char)(alaw^0xD5); //11010101
}
short CG711Decoder::decode(unsigned char alaw)
{
alaw ^= 0xD5;
int sign = alaw & 0x80;
int exponent = (alaw & 0x70) >> 4;
int data = alaw & 0x0f;
data <<= 4;
data += 8;
if (exponent != 0)
data += 0x100;
if (exponent > 1)
data <<= (exponent - 1);
return (short)(sign == 0 ? data : -data);
}