針對國內的博客或者技術論壇對 ILBC的論述都是把文章抄來抄去, 本人在此對 ILBC的具體代碼實現詳細列出代碼.
ILBC是由Global IP Sound公司提出的一種專為包交換網絡通信設計的編解碼,優於目前流行的G.729A、G.723.1,對丟包進行了特殊處理,既使在丟包率相當高的網絡環境下,仍可獲得非常清晰的語音效果。
ILBC 對於20 ms的幀,共使用了304個比特來表示編碼后的語音信號,被封裝在38個字節中;對於30ms的幀,共使用了480個比特,封裝在50個字節中。
1. ILBC的編譯
ILBC代碼部分是網絡上找的, 點此下載.
dll和lib(使用的是20 ms的幀) 點此下載.
2. 與PCM結合編解碼.
ILBC對WaveFormat的值有要求, 即下列代碼的@FFormat, 取其他值時會有問題.
PCMFormat: TWaveFormatEx = (
wFormatTag: WAVE_FORMAT_PCM;
nChannels: 1;
nSamplesPerSec: 8000;
nAvgBytesPerSec: 16000;
nBlockAlign: 2;
wBitsperSample: 16;
cbSize: 0 );
由於使用的是20 ms的幀, 1秒應該是回調50次, 每次的語音數據為320字節.
即FRecBufferSize的值取50
FDataSize:= FFormat.nAvgBytesPerSec div DWORD(RecBufferSize); GetMem(FWaveID,sizeof(HWaveIn)); i := WaveInOpen(FWaveID, WAVE_MAPPER, @FFormat, DWORD(@waveInCallback), DWORD(Self), CALLBACK_FUNCTION); if i=MMSYSERR_NOERROR then else begin FActive := False; Exit; end; for I:= 1 to FRecBufferSize do AddPrepareBuffer; WaveInStart(FWaveID^); FActive:= True;
以下函數為PCM數據回調后編碼
procedure TTalkClass.DoRecordData(Data: Pointer; size: Integer); var pEncodeBuf: array[0..37] of Byte; eSize: Integer; begin //先進行編碼 壓縮 eSize := ilbc_encoder(Data, @pEncodeBuf); if Assigned(FOnTalkData) then FOnTalkData(@pEncodeBuf, eSize); //已經編碼的數據 320->38 壓縮后的 end;
然后進行ilbc解碼和播放
function TTalkClass.PlayData(pData: PByte; size: Integer): Boolean; var pDecodeBuf: array [0..160-1] of SHORT; eSize: Integer; begin //傳入的是編碼后的數據 先解碼 eSize := ilbc_decoder(pData, @pDecodeBuf); FWaveOut.WriteData(@pDecodeBuf, eSize*2); end;
這個地方必須要注意eSize*2, 由於ilbc_decoder這個函數解碼后的數據為short型數組, 返回值eSize表示的是數組長度.
這個地方不注意的話, 就很有問題了.
再貼一下delphi中引用這個dll的代碼
const Dll = 'ilbc.dll'; function ilbc_init(): Boolean; stdcall; external Dll name '_ilbc_init@0'; function ilbc_encoder(pin: Pointer; pout: PByte): Integer; stdcall; external Dll name '_ilbc_encoder@8'; function ilbc_decoder(pin: PByte; pout: Pointer): Integer; stdcall; external Dll name '_ilbc_decoder@8';
需要編碼后的ilbc語音數據的點此下載. 用文件流讀取時記得每次取38字節進行解碼.
最后聲明下我說的只是個人這幾天的心得, 有什么說的不對的請指正.
