2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > android支持pcm格式转换 Android中Pcm文件转Amr文件

android支持pcm格式转换 Android中Pcm文件转Amr文件

时间:2022-12-16 19:00:33

相关推荐

android支持pcm格式转换 Android中Pcm文件转Amr文件

Android中Pcm文件转Amr文件

Android

最经在做一个聊天的模块,聊天的模块很简单:录音-上传-接收-播放

录音

录音部分可以采用MediaRecord和AudioRecord两个类进行录音.但是各有优缺点.

MediaRecord已经封装了很多方法,方便使用.

AudioRecord能获取录音的原生数据,以便对录音二次加工.

在录音过程我采用的是AudioRecord.但是AudioRecord录音数据是PCM格式,数据占用存储空间很大.必须压缩后才能传输.项目中的压缩是项目其他成员写的一个so库进行压缩的,有点不太方便.在网上翻阅了下,其实Android系统内部已经携带有压缩的库文件了.

压缩库

Android自带的有一个Pcm转amr的库:media_jni.so.

但是由于是Android系统内部的库,无法直接使用.根据网上的说明,最终终于弄明白如何使用了.

AmrInputStream

在要使用压缩库的项目中新建包:

com.android.media

在此包中新建AmrInputStream类,代码如下:

publicfinalclassAmrInputStreamextendsInputStream{

static{

System.loadLibrary("media_jni");

}

privatefinalstaticStringTAG="AmrInputStream";

// frame is 20 msec at 8.000 khz

privatefinalstaticintSAMPLES_PER_FRAME=8000*20/1000;

// pcm input stream

privateInputStreammInputStream;

// native handle

privateintmGae;

// result amr stream

privatebyte[]mBuf=newbyte[SAMPLES_PER_FRAME*2];

privateintmBufIn=0;

privateintmBufOut=0;

// helper for bytewise read()

privatebyte[]mOneByte=newbyte[1];

/**

* Create a new AmrInputStream, which converts 16 bit PCM to AMR

* @param inputStream InputStream containing 16 bit PCM.

*/

publicAmrInputStream(InputStreaminputStream){

mInputStream=inputStream;

mGae=GsmAmrEncoderNew();

GsmAmrEncoderInitialize(mGae);

}

@Override

publicintread()throwsIOException{

intrtn=read(mOneByte,0,1);

returnrtn==1?(0xff&mOneByte[0]):-1;

}

@Override

publicintread(byte[]b)throwsIOException{

returnread(b,0,b.length);

}

@Override

publicintread(byte[]b,intoffset,intlength)throwsIOException{

if(mGae==0)thrownewIllegalStateException("not open");

// local buffer of amr encoded audio empty

if(mBufOut>=mBufIn){

// reset the buffer

mBufOut=0;

mBufIn=0;

// fetch a 20 msec frame of pcm

for(inti=0;i

intn=mInputStream.read(mBuf,i,SAMPLES_PER_FRAME*2-i);

if(n==-1)return-1;

i+=n;

}

// encode it

mBufIn=GsmAmrEncoderEncode(mGae,mBuf,0,mBuf,0);

}

// return encoded audio to user

if(length>mBufIn-mBufOut)length=mBufIn-mBufOut;

System.arraycopy(mBuf,mBufOut,b,offset,length);

mBufOut+=length;

returnlength;

}

@Override

publicvoidclose()throwsIOException{

try{

if(mInputStream!=null)mInputStream.close();

}finally{

mInputStream=null;

try{

if(mGae!=0)GsmAmrEncoderCleanup(mGae);

}finally{

try{

if(mGae!=0)GsmAmrEncoderDelete(mGae);

}finally{

mGae=0;

}

}

}

}

@Override

protectedvoidfinalize()throwsThrowable{

if(mGae!=0){

close();

thrownewIllegalStateException("someone forgot to close AmrInputStream");

}

}

//

// AudioRecord JNI interface

//

privatestaticnativeintGsmAmrEncoderNew();

privatestaticnativevoidGsmAmrEncoderInitialize(intgae);

privatestaticnativeintGsmAmrEncoderEncode(intgae,

byte[]pcm,intpcmOffset,byte[]amr,intamrOffset)throwsIOException;

privatestaticnativevoidGsmAmrEncoderCleanup(intgae);

privatestaticnativevoidGsmAmrEncoderDelete(intgae);

}

AmrEmcoder

只有AmrInputStream类是不够,还需要一个转码的类AmrEncoder,代码如下:

publicclassAmrEncoder{

publicstaticvoidpcm2Amr(StringpcmPath,StringamrPath){

FileInputStreamfis;

try{

fis=newFileInputStream(pcmPath);

pcm2Amr(fis,amrPath);

fis.close();

}catch(FileNotFoundExceptione1){

e1.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

}

publicstaticvoidpcm2Amr(InputStreampcmStream,StringamrPath){

try{

AmrInputStreamais=newAmrInputStream(pcmStream);

OutputStreamout=newFileOutputStream(amrPath);

byte[]buf=newbyte[4096];

intlen=-1;

/*

* 下面的AMR的文件头,缺少这几个字节是不行的

*/

out.write(0x23);

out.write(0x21);

out.write(0x41);

out.write(0x4D);

out.write(0x52);

out.write(0x0A);

while((len=ais.read(buf))>0){

out.write(buf,0,len);

}

out.close();

ais.close();

}catch(FileNotFoundExceptione){

e.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

}

}

这里有两个方法:

1. pcm2Amr(String pcmPath , String amrPath): 将pcm文件转为amr文件

2. pcm2Amr(InputStream pcmStream, String amrPath): 将pcm数据流转为amr文件

测试

测试的界面

测试的界面很简单,就一个按钮一个文本显示,布局界面就不再给出,下面是MainActivity代码:

publicclassMainActivityextendsActivityimplementsOnClickListener{

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

}

privateTextViewhintView;

privateButtonstartButton;

privatevoidinitView(){

startButton=(Button)findViewById(R.id.btn_start);

startButton.setOnClickListener(this);

hintView=(TextView)findViewById(R.id.hint);

}

@Override

publicvoidonClick(Viewv){

if(v.getId()==R.id.btn_start){

transferButtonClicked();

}

}

privatevoidtransferButtonClicked(){

showWaitDialog();

startTransfer();

}

privateProgressDialogwaitDialog;

privatevoidshowWaitDialog(){

waitDialog=newProgressDialog(this);

waitDialog.setTitle(getResources().getString(R.string.transfer_wait_title));

waitDialog.setMessage(getResources().getString(R.string.transfer_wait_message));

waitDialog.show();

}

privatevoidstartTransfer(){

newTransferThread(this,newTransferCallback(){

@Override

publicvoidonSuccess(){

transferSuccess();

}

@Override

publicvoidonFailed(){

}

}).start();

}

privatevoidtransferSuccess(){

runOnUiThread(newRunnable(){

@Override

publicvoidrun(){

waitDialog.dismiss();

hintView.setText(getResources().getString(R.string.transfer_result));

ToastUtil.showShort(MainActivity.this,R.string.success_hint);

}

});

}

}

转换线程

由于文件转换是耗时操作,所以需要一个转换线程来实现文件转换.

publicclassTransferThreadextendsThread{

privateTransferCallbackcallback;

privateContextcontext;

publicTransferThread(Contextcontext,TransferCallbackcallback){

this.callback=callback;

this.context=context;

}

@Override

publicvoidrun(){

transfer();

}

privatevoidtransfer(){

StringrootPath=Environment.getExternalStorageDirectory().getPath();

StringamrPath=rootPath+"/test.amr";

try{

InputStreampcmStream=context.getAssets().open("test.pcm");

AmrEncoder.pcm2Amr(pcmStream,amrPath);

callback.onSuccess();

}catch(IOExceptione){

callback.onFailed();

e.printStackTrace();

}

}

publicstaticinterfaceTransferCallback{

voidonSuccess();

voidonFailed();

}

}

测试结果

经过测试,160KB的test.pcm压缩后的amr文件大小为15KB,且可以正常播放.

本文的项目文件在此:Pcm2Amr

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。