音频编解码之G726

音视频应用开发系列文章目录

在网上找了一份G726和PCM互相转化的代码(链接)。在VS2015下配置然后编译。使用附带的.pcm音频文件《上海滩》进行其demo代码测试,会发现成功运行但是有问题,pcm转成g726后,再将g726转成pcm,使用audacity进行pcm原始数据播放会发现声音变质了,就是转码有问题。本人基于其源码的(g726.c/g726.h)开发了一个g726转码类(AvG726),亲测可用。

源码g726.h

源代码有点长就不贴了,主要贴g726转码类(全部文件下载链接)

源码g726.c

源代码有点长就不贴了,主要贴g726转码类(全部文件下载链接)

g726转码类(AvG726.h)

#ifndef _AV_G726_H_
#define _AV_G726_H_

/***********************************************************
**	Author:kaychan
**	Data:2019-11-20
**  Mail:1203375695@qq.com
**	Explain:a g726 codec class base on g726codec source
***********************************************************/

#include "g726.h"
#include <string.h>
#include <stdlib.h>

typedef enum AvG726Bps_E{

	AvG726Bps_16K = 2,
	AvG726Bps_24K = 3,
	AvG726Bps_32K = 4,
	AvG726Bps_40K = 5,
}AvG726Bps;

class AvG726 {

public:
	AvG726(AvG726Bps bps = AvG726Bps_32K);
	~AvG726();
	int encode(unsigned char **odata, unsigned char *idata, int ilen);
	int decode(unsigned char **odata, unsigned char *idata, int ilen);
	void free_output_data(unsigned char *odata);

private:
	g726_state_t *g726_state_;
	AvG726Bps bps_;
};

#endif

g726转码类(AvG726.cpp)

#include "AvG726.h"

AvG726::AvG726(AvG726Bps bps) {

	g726_state_ = NULL;
	g726_state_ = (g726_state_t *)malloc(sizeof(g726_state_t));
	if (g726_state_) {

		bps_ = bps;
		g726_state_ = g726_init(g726_state_, 8000 * bps);
	}
}

AvG726::~AvG726() {

	free(g726_state_);
}

int AvG726::encode(unsigned char **odata, unsigned char *idata, int ilen) {

	if (g726_state_ && ilen > 0) {

		int olen = (int)((bps_ * 8000.) / 128000. * ilen);
		*odata = (unsigned char *)malloc(sizeof(unsigned char) * olen);
		if(*odata)
			return g726_encode(g726_state_, *odata, (short *)idata, ilen / 2);
	}
	return -1;
}

int AvG726::decode(unsigned char **odata, unsigned char *idata, int ilen) {

	if (g726_state_ && ilen > 0) {

		int olen = (int)(128000. / (bps_ * 8000.) * ilen);
		*odata = (unsigned char *)malloc(sizeof(unsigned char) * olen);
		if (*odata)
			return (2 * g726_decode(g726_state_, (short *)(*odata), idata, ilen));
	}
	return -1;
}

void AvG726::free_output_data(unsigned char *odata) {

	free(odata);
}

源码demo的bug

这里说下源码下demo的bug,demo的encode和decode的时候传入的输入数据的长度这个参数设置的不对。在encode的时候传入的数据长度为读取的pcm数据的一半g726_encode(g726_state_, *odata, (short *)idata, ilen / 2);,在decode的时候传入的数据长度为读取的g726的数据长度,但是在g726_decode函数返回的时候,返回的解码长度应该乘以2,才是真正的解码输出的pcm数据的长度return (2 * g726_decode(g726_state_, (short *)(*odata), idata, ilen));。并且这边通过枚举enum AvG726Bps_E可以精确的计算转码输出的长度olen大小以精确的分配内存,无需用户分配,但是需要用户使用函数void free_output_data(unsigned char *odata);释放内存。

olen的计算方法

encode的时候int olen = (int)((bps_ * 8000.) / 128000. * ilen);

因为raw pcm的比特率为128k,以编码为40kbps的g726为例,则bps_ = 5,5*8k = 40k,则压缩率为40k/128k,再乘以输入的长度可以算出编码后的数据大小,即olen。

decode的时候int olen = (int)(128000. / (bps_ * 8000.) * ilen);

同理,反过来即可算出解码后的pcm数据大小。

调用实例

编码

AvG726 g726(AvG726Bps_32K);
FILE *ifile = fopen("E:/sht.pcm", "rb");
FILE *ofile = fopen("E:/sht_32.g726", "wb");
unsigned char ibuf[200] = { 0 };
int rr = 1;
while (rr > 0) {

	rr = fread(ibuf, 1, 200, ifile);
	if (rr > 0) {

		unsigned char *obuf;
		int len = g726.encode(&obuf, ibuf, rr);
		fwrite(obuf, 1, len, ofile);
		g726.free_output_data(obuf);
		memset(ibuf, 0, sizeof(ibuf));
	}
}
fclose(ifile);
fclose(ofile);

解码

AvG726 g726(AvG726Bps_32K);
FILE *ifile = fopen("E:/sht_32.g726", "rb");
FILE *ofile = fopen("E:/sht_32.pcm", "wb");
unsigned char ibuf[200] = { 0 };
int rr = 1;
while (rr > 0) {

	rr = fread(ibuf, 1, 200, ifile);
	if (rr > 0) {

		unsigned char *obuf;
		int len = g726.decode(&obuf, ibuf, rr);
		fwrite(obuf, 1, len, ofile);
		g726.free_output_data(obuf);
		memset(ibuf, 0, sizeof(ibuf));
	}
}
fclose(ifile);
fclose(ofile);

遇到的问题

在使用raw pcm分别转成16k,24k,32k,40kbps的g726时,使用软件Toolsoft Audio Player播放G726时,16k,24k,40kbps完全听不清楚,沙沙沙的声音(ffplayer播放亦是如此),32kbps的可以听出声音,但是有杂音,不知道为何???,但是从改沙沙沙有问题的g726文件转回pcm数据,再去播放pcm声音却是正常的!说明编解码无问题。所以就纳闷了???

更多笔记

1.G726规定了如何将128kbps的raw pcm(64kbps的g711u/g711a)信号转为40kbps,32kbps,24kbps,16kbps的g726音频信号。

2.RTP载荷G726

3.ffmpeg-ffplayer音频播放命令

ffplay -f g726 -ar 8000 -ac 1 -code_size 3 -i xxx_24.g726 // asf类型g726
ffplay -f g726le -ar 8000 -ac 1 -code_size 3 -i xxx_24.g726 // RFC3551标准g726
ffplay -f s16le -ar 8000 -ac 1 -i xxx.pcm // pcm
ffplay -f alaw -ar 8000 -ac 1 -i 8k_1_16.g711a // g711a 8k 1ch 16bit
ffplay -f mulaw -ar 16000 -ac 2 -i 16k_2_16.g711u // g711u 16k 2ch 16bit	
ffplay -f aac -ar 44100 -ac 1 -i xxx.aac // aac samplerate@44100Hz

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值