一、概述
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)); } }