音頻編解碼之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:[email protected]
**	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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章