一、概述
G.711是国际电信联盟(ITU)为语音通信和录音等应用而制定的音频编解码标准。该标准主要用于传输纯语音信息,包括电话、对讲机等,不支持音频信号的压缩。G.711采用时域抽样,将模拟音频采样率从8kHz上升至16kHz,保证传输音频质量。
二、G.711编解码原理
G.711有两种编解码方式,分别为u-law(μ-law)和A-law。这两种编码方式是根据编码器的压缩特性进行选择的。
1. u-law编码
short linear2ulaw(int pcm_val)
{
int mask;
int seg;
unsigned char uval;
pcm_val = pcm_val >> 2;
if (pcm_val < 0) {
pcm_val = -pcm_val;
mask = 0x7F;
} else {
mask = 0xFF;
}
if (pcm_val > 0x3FFF) {
pcm_val = 0x3FFF;
}
pcm_val += 0x20;
seg = compand[pcm_val>>6];
uval = (unsigned char)(seg | ((pcm_val >> (seg + 1)) & 0x0F));
return (short)(uval ^ mask);
}
2. A-law编码
short linear2alaw(int pcm_val)
{
int mask;
int seg;
unsigned char aval;
if (pcm_val >= 0) {
mask = 0xD5;
} else {
mask = 0x55;
pcm_val = -pcm_val - 8;
}
if (pcm_val < 0) {
pcm_val = 0;
}
if (pcm_val > 0x7FF) {
pcm_val = 0x7FF;
}
pcm_val >>= 4;
seg = search(pcm_val, seg_end, 8);
if (seg >= 8) {
return (short)(0x7F ^ mask);
} else {
aval = (unsigned char)(seg << 4 | (pcm_val >> (seg + 1) & 0x0F));
return (short)(aval ^ mask);
}
}
三、G.711编码器的实现
以下代码展示了一个简单的G.711编码器实现:
public class G711Encoder {
static final int ZEROTRAP = 1;
static final int BIAS = 0x84;
static final int CLIP = 8159;
private static byte[] _law2linear;
/**
* 静态块,初始化_law2linear表
*/
static {
_law2linear = new byte[1024];
for (int i = 0; i < 256; i++) {
int x = i ^ 0x55;
x <<= 7;
short t = (short) x;
if ((x & 0x8000) != 0) {
t = (short) (0x7fff - (x & 0x7fff));
}
t -= BIAS << 7;
_law2linear[i] = (byte) (t >>> 8);
_law2linear[i + 256] = (byte) (t & 0xff);
x = (i & 0x7f) << 8;
t = (short) x;
if ((x & 0x8000) != 0) {
t = (short) (0x7fff - (x & 0x7fff));
}
t -= (BIAS << 3) - 1;
_law2linear[i + 512] = (byte) (t >>> 8);
_law2linear[i + 768] = (byte) (t & 0xff);
}
}
/**
* 编码PCM到G.711
*
* @param pcm 输入PCM数据
* @return 返回G.711编码后的数据
*/
public byte[] encode(byte[] pcm) {
byte[] g711 = new byte[pcm.length / 2];
int idx, x;
for (int i = 0, s = 0; i < pcm.length; i += 2) {
idx = ((pcm[i + 1] & 0xff) << 8) | (pcm[i] & 0xff);
if (idx < 0) {
idx = 0;
} else if (idx > 32767) {
idx = 32767;
}
x = _law2linear[idx];
if (pcm[i + 1] < 0) {
x = -x;
}
x += 0x80;
if (x < 0) {
x = 0;
} else if (x > 0xFF) {
x = 0xFF;
}
g711[s++] = (byte) x;
}
return g711;
}
}
四、G.711解码器的实现
以下代码展示了一个简单的G.711解码器实现:
public class G711Decoder {
static final int ZEROTRAP = 1;
static final int BIAS = 0x84;
static final int CLIP = 8159;
private static short[] _linear2law;
/**
* 静态块,初始化_linear2law表
*/
static {
int[] seg_end = {0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
_linear2law = new short[65536];
for (int i = 0; i < 65536; i++) {
short sign = 0;
if (i < 0) {
i = -i;
sign = 0x80;
}
int exponent = search(i, seg_end, 8) << 3;
int mantissa = (i >> (exponent + 3)) & 0x0F;
_linear2law[i] = (short) (sign | exponent | mantissa);
}
}
/**
* 解码G.711到PCM
*
* @param g711 输入G.711数据
* @return 返回PCM解码后的数据
*/
public byte[] decode(byte[] g711) {
byte[] pcm = new byte[g711.length * 2];
int idx, sign, x;
for (int i = 0, s = 0; i < g711.length; i++, s += 2) {
sign = (g711[i] & 0x80) != 0 ? (byte) 0x00FF : 0;
idx = ((g711[i] ^ sign) & 0xff);
x = _linear2law[idx] + BIAS << 7;
if (sign != 0) {
x = -x;
}
pcm[s] = (byte) (x & 0xff);
pcm[s + 1] = (byte) (x >> 8);
}
return pcm;
}
}
五、应用举例
G.711主要在电话语音通信、对讲机等领域中得到广泛使用。以下是一个Java语言中使用G.711编解码的例子:
public class G711Example {
public static void main(String[] args) {
short[] pcmData = new short[]{0, 100, 200, 300, 400, 500};
G711Encoder encoder = new G711Encoder();
G711Decoder decoder = new G711Decoder();
byte[] g711Data = encoder.encode(ArrayUtils.toBytes(pcmData)); // PCM -> G.711
short[] pcmData2 = ArrayUtils.toShorts(decoder.decode(g711Data)); // G.711 -> PCM
System.out.println(Arrays.toString(pcmData));
System.out.println(Bytes.toHexString(g711Data, "", " ", ""));
System.out.println(Arrays.toString(pcmData2));
}
}