在網上找了一份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音頻信號。
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