[音频]G711编码原理学习及代码

介绍

g711常用在嵌入式方面,采样率为8k。g711 标准下主要有两种压缩算法。一种是u-law,另一种是A-law。两者都是对一个采样进行压缩,区别在于g711-a将13位转换为8位压缩数据,g711-u将14位转换为8位压缩数据。
压缩比固定为:
8/14 = 57% (uLaw)
8/13 = 62% (aLaw)
但事实上写代码的时候,常常将16位转换位8位。压缩比为50%
在这里插入图片描述

测试一下

模拟201个16位音频采样数据 区间在[-10000–10000]
转换为8位的g711a压缩数据再转换回来
在这里插入图片描述
将数据用matlab上显示出来
蓝色为pcm采样数据
红色为g711a压缩数据(相对16位变化不明显)
橙色为压缩后再解压缩的pcm数据
可以很明显看到在低频段的数据是最精准的,频率越高声音的失真是越大的。这是由于g711采用非线性量化–对数量化在这里插入图片描述

对数量化

由于语声的小信号出现概率大,大信号出现概率小,所以需要对小信号更加精准,大信号相对粗略点。
在这里插入图片描述

对数量化的实现

如G711A使用压缩十三折线法
g711a输入的是13位(S16的高13位),这种格式是经过特别设计的,便于数字设备进行快速运算。

1、取符号位并取反得到s
2、获取强度位eee
3、获取高位样本位wxyz
4、组合为seeewxyz,将seeewxyz逢偶数为取补数,编码完毕

将红线(g711a压缩数据)放大看看

在这里插入图片描述

代码

经过验证可行,方便以后使用

#define SIGN_BIT (0x80)
#define QUANT_MASK (0xf)
#define NSEGS (8)
#define SEG_SHIFT (4)
#define SEG_MASK (0x70)
#define BIAS (0x84)

#define int16_t short
#define uint8_t unsigned char 
#define uint32_t unsigned long


#define LENGTH 400

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));
}


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 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;
}
编码

static short seg_aend[8] = {
	0x1F, 0x3F, 0x7F, 0xFF,
	0x1FF, 0x3FF, 0x7FF, 0xFFF
};

static short 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(static int pcm_val)/* 2's complement (16-bit range) */
{

	int mask;
	int seg;
	unsigned char aval;

	pcm_val = pcm_val >> 3;

	if (pcm_val >= 0) {
		mask = 0xD5;/* sign (7th) bit = 1 */
	}
	else {
		mask = 0x55;/* sign bit = 0 */
		pcm_val = -pcm_val - 1;
	}

	/* Convert the scaled magnitude to segment number.
	将缩放的幅度转换为段数
	*/
	seg = search(pcm_val, seg_aend, 8);

	/* Combine the sign, segment, and quantization bits.
	组合符号,分段和量化位
	*/

	if (seg >= 8)/* out of range, return maximum value. */
		return (unsigned char)(0x7F ^ mask);
	else {
		aval = (unsigned char)seg << SEG_SHIFT;
		if (seg < 2)
			aval |= (pcm_val >> 1) & QUANT_MASK;
		else
			aval |= (pcm_val >> seg) & QUANT_MASK;
		return (aval ^ mask);
	}

}

int main()
{
	FILE * fp_in = fopen("./x64/g711.pcm","rb");
	FILE * fp_out = fopen("./x64/out_audio.pcm", "wb");

	char in_buf[LENGTH];
	char out_buf[LENGTH*2];//输出为输入2倍
	int in_len = LENGTH;
	int out_len = LENGTH * 2;
	if (!fp_in||!fp_out)
	{
		printf("error open file\n");
		return -1;
	}
	while (LENGTH == fread(&in_buf, 1, LENGTH, fp_in))
	{
		g711_decode(out_buf, &out_len,&in_buf, LENGTH, TP_ALAW);
		fwrite(out_buf, 1, out_len, fp_out);
		printf("send %d\n",out_len);
	}

	fclose(fp_in);
	fclose(fp_out);
	return 1;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工农村贴膜小哥

我倒是要看看是那个憨憨在给我打

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值