iOS PCMAudio 与 g711a/g711u 的互转码
iOS G711编码
G.711是一种由国际电信联盟(ITU-T)制定的音频编码方式,又称为ITU-T G.711。
它是国际电信联盟ITU-T定制出来的一套语音压缩标准,它代表了对数PCM(logarithmic pulse-code modulation)抽样标准,主要用于电话。它主要用脉冲编码调制对音频采样,采样率为8k每秒。它利用一个 64Kbps 未压缩通道传输语音讯号。 起压缩率为1:2, 即把16位数据压缩成8位。G.711是主流的波形声音编解码器。
G.711 标准下主要有两种压缩算法。
一种是µ-law algorithm (又称often u-law, ulaw, mu-law),主要运用于北美和日本;
另一种是A-law algorithm,主要运用于欧洲和世界其他地区。其中,后者是特别设计用来方便计算机处理的。
G711A(A-LAW)压缩算法
(1)取符号位并取反得到s
(2)获取强度位eee,获取方法如图所示
(3)获取高位样本位wxyz
(4)组合为seeewxyz,将seeewxyz逢偶数为取补数,编码完毕
输入pcm数据为1234,二进制对应为(0000 0100 1101 0010)
二进制变换下排列组合方式(0 00001 0011 010010)
(1)获取符号位最高位为0,取反,s=1
(2)获取强度位00001,查表,编码制应该是eee=011
(3)获取高位样本wxyz=0011
(4)组合为10110011,逢偶数为取反为11100110
编码完毕。
G711U(U-LAW)压缩算法
通过查表,计算出:基础值+平均偏移值
输入pcm数据为1234
(1)取得范围值,查表得+2014 to +991 in 16 intervals of 64
(2)得到基础值为0xA0
(3)得到间隔数为64
(4)得到区间基本值2014
(5)当前值1234和区间基本值差异2014-1234=780
(6)偏移值=780/间隔数=780/64,取整得到12
(7)输出为0xA0+12=0xAC
编码完毕。
code如下
#import <Foundation/Foundation.h> @interface EncoderG711 : NSObject - (unsigned char)linear2alaw:(int)pcm_val; - (unsigned char)linear2ulaw:(int)pcm_val; @end #import "EncoderG711.h" #define QUANT_MASK (0xf) #define SEG_SHIFT (4) #define BIAS (0x84) @implementation EncoderG711 static short seg_end[8] = {0xFF,0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF}; static int search(int val,short *table,int size) { int i; for (i = 0; i < size; i++) { if (val <= *table++) return (i); } return (size); } - (unsigned char)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; } seg = search(pcm_val, seg_end, 8); if (seg >= 8) return (0x7F ^ mask); else { aval = seg << SEG_SHIFT; if (seg < 2) aval |= (pcm_val >> 4) & QUANT_MASK; else aval |= (pcm_val >> (seg + 3)) & QUANT_MASK; return (aval ^ mask); } } - (unsigned char)linear2ulaw:(int)pcm_val { int mask; int seg; unsigned char uval; if (pcm_val < 0) { pcm_val = BIAS - pcm_val; mask = 0x7F; } else { pcm_val += BIAS; mask = 0xFF; } seg = search(pcm_val, seg_end, 8); if (seg >= 8) return (0x7F ^ mask); else { uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF); return (uval ^ mask); } } @end - (NSData *)encodeG711:(NSData *)data { NSUInteger datalength = [data length]; Byte *byteData = (Byte *)[data bytes]; short *pPcm = (short *)byteData; free(byteData); int outlen = 0; int len =(int)datalength/2; Byte *G711Buff = (Byte *)malloc(len); memset(G711Buff,0,len); int i; for (i=0; i<len; i++) { if (_type==G711A) { G711Buff[i] = [_g711 linear2alaw:pPcm[i]]; } else if (_type==G711U) { G711Buff[i] = [_g711 linear2ulaw:pPcm[i]]; } } outlen = i; Byte *sendbuff = (Byte *)G711Buff; NSData *sendData = [[NSData alloc] initWithBytes:sendbuff length:len]; free(G711Buff); return sendData; }
iOS G711解码
#import <Foundation/Foundation.h> @interface DecoderG711 : NSObject enum _e_g711_tp { TP_ALAW, TP_ULAW }; int g711_decode(void *pout_buf, int *pout_len, const void *pin_buf, const int in_len , int type); @end #import "DecoderG711.h" #define SIGN_BIT (0x80) #define QUANT_MASK (0xf) #define NSEGS (8) #define SEG_SHIFT (4) #define SEG_MASK (0x70) #define BIAS (0x84) @interface DecoderG711() @end @implementation DecoderG711 int g711_decode(void *pout_buf, int *pout_len, const void *pin_buf, const int in_len , int type) { int16_t *dst = (int16_t *) pout_buf; uint8_t *src = (uint8_t *) pin_buf; uint32_t i = 0; int Ret = 0; if ((NULL == pout_buf) || \ (NULL == pout_len) || \ (NULL == pin_buf) || \ (0 == in_len)) { return -1; } if (*pout_len < 2 * in_len) { return -2; } if (TP_ALAW == type) { for (i = 0; i < in_len; i++) { *(dst++) = (int16_t)alaw2linear(*(src++)); } } else { for (i = 0; i < in_len; i++) { *(dst++) = (int16_t)ulaw2linear(*(src++)); } } *pout_len = 2 * in_len; Ret = 2 * in_len; return Ret; } int alaw2linear(unsigned char a_val) { int t; int seg; a_val ^= 0x55; t = (a_val & QUANT_MASK) << 4; seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; switch (seg) { case 0: t += 8; break; case 1: t += 0x108; break; default: t += 0x108; t <<= seg - 1; } return ((a_val & SIGN_BIT) ? t : -t); } int ulaw2linear(unsigned char u_val) { int t; u_val = ~u_val; t = ((u_val & QUANT_MASK) << 3) + BIAS; t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); } @end - (void)decoderG711:(NSData *)data { NSUInteger datalength = [data length]; Byte *byteData = (Byte *)[data bytes]; int inlen = (int)datalength; short *g711Buf = (short *)byteData; int outlen = inlen * 2; Byte *pcmBuf = (Byte *)malloc(outlen); g711_decode(pcmBuf, &outlen, g711Buf, inlen, TP_ALAW); NSData *pcm = [[NSData alloc] initWithBytes:pcmBuf length:outlen]; free(pcmBuf); [_aqplayer playWithData:pcm]; }