我们都知道,现在手机的录音大部分都采用amr格式。对于人声,amr可以做到很高的压缩率(例如:1k bytes/sec),非常方面网络传输。
可是,现在电脑上能解码amr文件的软件不是很多,甚至有些big公司的播放器居然在播放amr文件的时候声音很嘈杂混乱。
利用OpenCore的amr编码解码算法,可以很方便的对amr文件进行解码,既可以把amr转换成wav文件,还可以实现边解码边播放。
首先,下载OpenCore AMR:http://sourceforge.net/projects/opencore-amr/,版本可以选择0.1.3。
然后,用Ming对下载的C语言工程进行编译(很慢,很low,我的机器编译过程花了近2个小时),编译后,找到一个dll文件:libopencore-amrnb.dll
最后,我们用delphi调用这个dll中的三个函数,实现解码:
function Decoder_Interface_init():pointer;cdecl;external 'libopencore-amrnb.dll';
procedure Decoder_Interface_exit(state:pointer);cdecl;external 'libopencore-amrnb.dll';
procedure Decoder_Interface_Decode(state:pointer; DataIn:pbyte; DataOut:pword; bfi:integer);cdecl;external 'libopencore-amrnb.dll';
-------------------------------分割线-------------------
procedure TAmrThread.Amr2WavNB();
var
amr:pointer;
FileAmr:TFileStream;
FileWav:TFileStream;
n,_size,i:integer;
buffer:array [0..499] of byte;
littleendian:array [0..319] of byte;
outbuffer:array[0..159] of Word;
ptr:PByte;
_sizes:array [0..15] of integer = (12, 13, 15, 17, 19, 20, 26, 31, 5, 6, 5, 5, 0, 0, 0, 0 );
begin
percent:=0;
AmrErrorMsg:='';
FileAmr:=TFileStream.Create(AmrFileName+'.amr',fmOpenRead);
if FileAmr=nil then begin
percent:=100;
AmrErrorMsg:='failed to open amr file.';
exit;
end;
FileAmr.Position:=7;
FileWav:= CreateWav(1,16,8000,'FromAmr.wav');
if FileWav=nil then begin
percent:=100;
AmrErrorMsg:='failed to create wav file.';
exit;
end;
amr:=Decoder_Interface_init();
while true do begin
// Read the mode byte
while true do begin
n := FileAmr.Read(buffer, 1);
if (n <= 0) then break;
if ((buffer[0] and 4)=4) then break; //bit2=0 means error frame
end;
if (n<=0) then break;
// Find the packet size
_size := _sizes[(buffer[0] >> 3) and 15];
if _size<=0 then continue;
n := FileAmr.Read(buffer[1], _size); //@buffer[1]
if (n <> _size) then break;
// Decode the packet
Decoder_Interface_Decode(amr, buffer, outbuffer, 0);
// Convert to little endian and write to wav
ptr := littleendian;
for i := 0 to 159 do begin
ptr^:= (outbuffer[i] shr 0) and 255; inc(ptr); //*ptr++ = (outbuffer[i] >> 0) & 0xff;
ptr^:= (outbuffer[i] shr 8) and 255; inc(ptr); //*ptr++ = (outbuffer[i] >> 8) & 0xff;
end;
FileWav.Write(littleendian, 320);
percent:=100*FileAmr.Position div FileAmr.Size;
PostMessage(HMainForm,WM_DEAL_AMR,0,0);
end;
Decoder_Interface_exit(amr);
CloseWavFile(FileWav);
FileAmr.Free;
percent:=100;
end;
function CreateWav( channels : word; { 1(单声)或者2(立体声) }
resolution : word; { 8或者16,代表8位或16位声音 }
rate : longint; { 声音频率,如11025,22050, 44100}
fn : string { 对应的文件名称 } ):TFileStream;
var
wf : TFileStream;
wh : TWavHeader;
begin
wh.rId := $46464952;
wh.rLen := 36;
wh.wId := $45564157;
wh.fId := $20746d66;
wh.fLen := 16;
wh.wFormatTag := 1;
wh.nChannels := channels;
wh.nSamplesPerSec := rate;
wh.nAvgBytesPerSec := channels*rate*(resolution div 8);
wh.nBlockAlign := channels*(resolution div 8);
wh.wBitsPerSample := resolution;
wh.dId := $61746164;
wh.wSampleLength := 0;
Result:=nil;
try
wf:=TFileStream.Create(fn,fmCreate or fmShareDenyNone);
wf.Write(wh,sizeOf(wh));
Result:=wf;
except
end;
end;
procedure CloseWavFile(f:TFileStream);
var
DataSize:integer;
begin
DataSize:=f.Size -8;
f.Seek(4,soFromBeginning); //写RIFF之后的4个字节
f.Write(DataSize,sizeOf(DataSize));
DataSize:=DataSize-36;
f.Seek(40,soFromBeginning);//写data之后的4个字节
f.Write(DataSize,sizeOf(DataSize));
f.Free ;
end;
----------------------------------------------
webliv,西安国咨软件。如要引用请注明出处。