热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android开发分享Android开发MediaCodec和lamemp3多段音频截取拼接

截取很简单,只要用mediacodec进行解码解出pcm格式的数据,再把pcm数据用mediacodec进行编码或者用其他第三方的进行编码。拼接就比较麻烦,音频的音质会受到采样率

截取很简单,只要用mediacodec进行解码解出pcm格式的数据,再把pcm数据用mediacodec进行编码或者用其他第三方的进行编码 。

上述就是android开发分享Android开发MediaCodec和lamemp3多段音频截取拼接的全部内容,如果对大家有所用处且需要了解更多关于Android学习教程,希望大家多多关注—编程笔记

拼接就比较麻烦,音频的音质会受到采样率,比特率和声道的影响,所以理想的状态是这三个属性要一样进行拼接才能保证音质 。

举个栗子,a和b是两首采样率,比特率和声道都不一样的歌,要拼接成c,首先要设置c的采样率,比特率和声道,这里用a的来进行设置,然后拼接,播放c的时候会发现a部分的音质是没问题的,到了b部分的时候音质就会出现问题。

解决这个问题很简单,先把a和b的采样率,比特率和声道都转成一样就可以了。对于音视频开发的人来说这个问题很好解决,就写个转换采样率,比特率和声道的工具,或者使用 ffmpeg。

通过github找到了几个,经过测试最后选择了lamemp3,lamemp3是c语言写的,怎么编译网上很多就不说了,好了开始正题 。

首先说说思路,先通过mediacodec把要处理的几个音频解码出pcm文件,再把这些pcm文件通过lamemp3转成采样率,比特率和声道一样的mp3,再通过mediacodec把这些mp3合并成一个pcm数据,最后就是把这个pcm数据转成自己想要的格式,可以用mediacodec转成aac或者用lamemp3再转成mp3。

audioholder.java属性类

记录音频的采样率,比特率,声道,截取的开始时间,截取的结束时间,路径和文件名

public class audioholder {      private string file;      private string name;      private double start;      private double end;        private int samplerate;      private int channelcount;      private int bitrate;        private string mp3;        public void setmp3(string mp3) {          this.mp3 = mp3;      }        public string getmp3() {          return mp3;      }        public string getfile() {          return file;      }        public void setfile(string file) {          this.file = file;      }        public string getname() {          return name;      }        public void setname(string name) {          this.name = name;      }        public double getstart() {          return start;      }        public void setstart(double start) {          this.start = start;      }        public double getend() {          return end;      }        public void setend(double end) {          this.end = end;      }        public int getsamplerate() {          return samplerate;      }        public void setsamplerate(int samplerate) {          this.samplerate = samplerate;      }        public int getchannelcount() {          return channelcount;      }        public void setchannelcount(int channelcount) {          this.channelcount = channelcount;      }        public int getbitrate() {          return bitrate;      }        public void setbitrate(int bitrate) {          this.bitrate = bitrate;      }  }

simplelame.java调用lamemp3类

public class simplelame {      static {          system.loadlibrary("native-lib");      }      /**       * pcm文件转换mp3函数       */      public static native void convert(audioencoder encoder,string jwav, string jmp3,                                        int insamplerate, int outchannel, int outsamplerate, int outbitrate,                                        int quality);  }

native-lib.cpp

#include   #include   #include "lamemp3/lame.h"  #include     #define inbufsize 4096  #define mp3bufsize (int) (1.25 * inbufsize) + 7200    extern "c"  jniexport void jnicall  java_com_hyq_hm_audiomerge_lame_simplelame_convert(jnienv *env, jclass type, jobject encoder,                                                     jstring jwav_,jstring jmp3_,                                                     jint insamplerate,jint outchannel,                                                     jint outsamplerate,jint outbitrate,                                                     jint quality) {      const char *jwav = env->getstringutfchars(jwav_, 0);      const char *jmp3 = env->getstringutfchars(jmp3_, 0);      // todo      short int wav_buffer[inbufsize*outchannel];      unsigned char mp3_buffer[mp3bufsize];  //    获取文件大小      struct stat st;      stat(jwav, &st );      jclass cls = env->getobjectclass(encoder);      jmethodid mid = env->getmethodid(cls, "setprogress", "(jj)v");        file* fwav = fopen(jwav,"rb");      file* fmp3 = fopen(jmp3,"wb");      lame_t lamecOnvert=  lame_init();        lame_set_in_samplerate(lameconvert , insamplerate);      lame_set_out_samplerate(lameconvert, outsamplerate);      lame_set_num_channels(lameconvert,outchannel);  //    lame_set_vbr(lameconvert,vbr_mtrh);  //    lame_set_vbr_mean_bitrate_kbps(lameconvert,outbitrate);      lame_set_brate(lameconvert,outbitrate);      lame_set_quality(lameconvert, quality);      lame_init_params(lameconvert);        int read ; int write;      long total=0;      do{          read = (int) fread(wav_buffer, sizeof(short int) * outchannel, inbufsize, fwav);          total +=  read* sizeof(short int)*outchannel;          env->callvoidmethod(encoder,mid,(long)st.st_size,total);          if(read!=0){              if (outchannel == 2){                  write = lame_encode_buffer_interleaved(lameconvert,wav_buffer,read,mp3_buffer,mp3bufsize);              }else{                  write = lame_encode_buffer(lameconvert,wav_buffer,wav_buffer,read,mp3_buffer,mp3bufsize);              }          } else{              write = lame_encode_flush(lameconvert,mp3_buffer,mp3bufsize);          }          fwrite(mp3_buffer, sizeof(unsigned char), (size_t) write, fmp3);      }while (read!=0);      lame_mp3_tags_fid(lameconvert,fmp3);      lame_close(lameconvert);      fclose(fwav);      fclose(fmp3);        env->releasestringutfchars(jwav_, jwav);      env->releasestringutfchars(jmp3_, jmp3);  }

audiomerge.java拼接操作类

public class audiomerge {      private static final string audio = "audio/";        private handler audiohandler;      private handlerthread audiothread;      public audiomerge(){          audiothread = new handlerthread("audiomerge");          audiothread.start();          audiohandler = new handler(audiothread.getlooper());      }      private onaudioencoderlistener encoderlistener;        public void setencoderlistener(onaudioencoderlistener encoderlistener) {          this.encoderlistener = encoderlistener;      }        public void start(final string path, final list list){          audiohandler.post(new runnable() {              @override              public void run() {                  encoders(path,list);              }          });      }        public void start(final string path, final list list,onaudioencoderlistener encoderlistener){          this.encoderlistener = encoderlistener;          start(path,list);      }      private static int[] samplerates = {48000,44100,32000,24000,22050,16000,12000,11025,8000};      private static int[] mpeg1bitrates = {320,256,224,192,160,128,112,96,80,64,56,48,40,32};      private static int[] mpeg2bitrates = {160,144,128,112,96,80,64,56,48,40,32,24,16,8};      private static int[] mpeg25bitrates = {64,56,48,40,32,24,16,8};        private int audiotrackindex;      private audioholder decoderholder = null;      /**       * 进行解码和拼接       */      private void encoders(string path,list list){          file file = new file(path);          if(file.exists()){              file.delete();          }          //统一采样率,比特率和声道          int bitrate = list.get(0).getbitrate();          int samplerate = list.get(0).getsamplerate();          int channelcount = list.get(0).getchannelcount();          if(list.size() != 1){              for (audioholder holder:list){                  bitrate = math.min(bitrate,holder.getbitrate());                  samplerate = math.min(samplerate,holder.getsamplerate());                  channelcount = math.min(channelcount,holder.getchannelcount());              }              samplerate = format(samplerate,samplerates);              if(samplerate >= samplerates[2]){                  bitrate = format(bitrate,mpeg1bitrates);              }else if(samplerate <= samplerates[6]){                  bitrate = format(bitrate,mpeg25bitrates);              }else{                  bitrate = format(bitrate,mpeg2bitrates);              }          }            //临时用的pcm文件          string pcm = environment.getexternalstoragedirectory().getabsolutepath()+"/hmsdk/"+system.currenttimemillis()+".pcm";          list mp3s = new arraylist<>();          //总时长,用来计算进度用的          long duration = 0;          for (audioholder holder :list){              //只有1个音频的时候直接转mp3              string mp3;              if(list.size() == 1){                  mp3 = path;                  decoderholder = null;              }else{                  decoderholder = holder;                  mp3 = environment.getexternalstoragedirectory().getabsolutepath()+"/hmsdk/"+system.currenttimemillis()+".mp3";              }              //将音频解码成pcm文件              duration += decoderpcm(holder,pcm);              //把pcm文件转成mp3              simplelame.convert(this,pcm,mp3                      ,holder.getsamplerate(),                      channelcount,samplerate,bitrate,                      1              );              mp3s.add(mp3);          }          //只有一个音频就完成操作          if(list.size() == 1){              if(encoderlistener != null){                  encoderlistener.onover(path);              }              return;          }          //以下可换成其他代码,比如用mediacodec转成aac,因为采样率,比特率和声道都是一样的文件          decoderholder = null;          file f = new file(pcm);          if(f.exists()){              f.delete();          }          outputstream pcmos = null;          try {              pcmos = new fileoutputstream(pcm);          } catch (filenotfoundexception e) {              e.printstacktrace();          }          //文件总大小          long total = 0;          for (string mp3 : mp3s){              //将mp3转成pcm文件返回转换数据的大小              total += encodermp3(mp3,pcmos,total,duration);          }          try {              pcmos.flush();              pcmos.close();          } catch (ioexception e) {              e.printstacktrace();          }          //把pcm文件转成mp3          simplelame.convert(this,pcm,path                  ,samplerate,                  channelcount,samplerate,bitrate,                  1          );          if(encoderlistener != null){              encoderlistener.onover(path);          }        }      /**       * 进行解码       */      private long decoderpcm(audioholder holder,string pcm){          long starttime = (long) (holder.getstart()*1000*1000);          long endtime = (long) (holder.getend()*1000*1000);          //初始化mediaextractor和mediacodec          mediaextractor audioextractor = new mediaextractor();          mediacodec audiodecoder = null;          try {              audioextractor.setdatasource(holder.getfile());              for (int i = 0; i = 0) {                  bytebuffer data = audiodecoder.getoutputbuffer(outindex);                  if ((info.flags & mediacodec.buffer_flag_codec_config) != 0) {                      info.size = 0;                  }                  if (info.size != 0) {                      //判断解码出来的数据是否在截取的范围内                      if(info.presentationtimeus >= starttime && info.presentationtimeus <= endtime){                          byte[] bytes = new byte[data.remaining()];                          data.get(bytes,0,bytes.length);                          data.clear();                          //写入pcm文件                          try {                              pcmos.write(bytes);                          } catch (ioexception e) {                              e.printstacktrace();                          }                          //进度条                          if(encoderlistener != null){                              int progress = (int) (((info.presentationtimeus - starttime)*50)/duration);                              if(decoderholder == null){                                  encoderlistener.onencoder(progress);                              }else{                                  encoderlistener.ondecoder(decoderholder,progress);                              }                          }                      }                  }                  audiodecoder.releaseoutputbuffer(outindex, false);                  //超过截取时间结束解码                  if(info.presentationtimeus >= endtime){                      break;                  }              }              if ((info.flags & mediacodec.buffer_flag_end_of_stream) != 0) {                  break;              }          }          try {              pcmos.flush();              pcmos.close();          } catch (ioexception e) {              e.printstacktrace();          }          audiodecoder.stop();          audiodecoder.release();          audioextractor.release();          return duration;      }      /**       * mp3转pcm       */      private long encodermp3(string mp3,outputstream pcmos,long starttime,long duration){          long d = 0;          mediaextractor audioextractor = new mediaextractor();          mediacodec audiodecoder = null;          try {              audioextractor.setdatasource(mp3);              for (int i = 0; i = 0) {                  bytebuffer data = audiodecoder.getoutputbuffer(outindex);                  if ((info.flags & mediacodec.buffer_flag_codec_config) != 0) {                      info.size = 0;                  }                  if (info.size != 0) {                      byte[] bytes = new byte[data.remaining()];                      data.get(bytes,0,bytes.length);                      data.clear();                      try {                          pcmos.write(bytes);                      } catch (ioexception e) {                          e.printstacktrace();                      }                      if(encoderlistener != null){                          int progress = (int) (((info.presentationtimeus + starttime)*50)/duration);                          encoderlistener.onencoder(progress);                      }                  }                  audiodecoder.releaseoutputbuffer(outindex, false);              }              if ((info.flags & mediacodec.buffer_flag_end_of_stream) != 0) {                  break;              }          }          audiodecoder.stop();          audiodecoder.release();          audioextractor.release();          return d;      }      private void extractorinputbuffer(mediaextractor mediaextractor, mediacodec mediacodec) {          int inputindex = mediacodec.dequeueinputbuffer(50000);          if (inputindex >= 0) {              bytebuffer inputbuffer = mediacodec.getinputbuffer(inputindex);              long sampletime = mediaextractor.getsampletime();              int samplesize = mediaextractor.readsampledata(inputbuffer, 0);              if (mediaextractor.advance()) {                  mediacodec.queueinputbuffer(inputindex, 0, samplesize, sampletime, 0);              } else {                  if (samplesize > 0) {                      mediacodec.queueinputbuffer(inputindex, 0, samplesize, sampletime, mediacodec.buffer_flag_end_of_stream);                  } else {                      mediacodec.queueinputbuffer(inputindex, 0, 0, 0, mediacodec.buffer_flag_end_of_stream);                  }              }          }      }      private int format(int f,int[] fs){          if(f >= fs[0]){              return fs[0];          }else if(f <= fs[fs.length - 1]){              return fs[fs.length - 1];          }else{              for (int i = 1; i = fs[i]){                      return fs[i];                  }              }          }          return -1;      }      /**       * jni回调的进度条函数,进度条以解码占50,pcm转mp3占50       */      public void setprogress(long size,long total){          if(encoderlistener != null){              int progress = 50 + (int) ((total*50)/size);              if(decoderholder == null){                  encoderlistener.onencoder(progress);              }else{                  encoderlistener.ondecoder(decoderholder,progress);              }          }      }        public interface onaudioencoderlistener{          void ondecoder(audioholder decoderholder,int progress);          void onencoder(int progress);          void onover(string path);      }    } 

使用

private audiomerge audiomerge = new audiomerge();  private list list = new arraylist<>();
audiomerge.start(environment.getexternalstoragedirectory().getabsolutepath()+"/hmsdk/test_merge.mp3",list);  

还有hmsdk这个文件夹自己创建或改成自己的,我都是保存在手机内是为了方便测试

github: https://github.com/a422070876/audiomerge

以上就是android开发mediacodec和lamemp3多段音频截取拼接的详细内容,更多关于mediacodec和lamemp3音频截取拼接的资料请关注<编程笔记>其它相关文章!


推荐阅读
author-avatar
H801_597
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有