概述

在Android上实现录音,并利用 FFmpeg将PCM数据编码成AAC。

详细

代码下载:http://www.demodashi.com/demo/10512.html


之前做的一个demo,Android录音获取pcm数据(音频原始数据),然后利用 FFmpeg将PCM数据编码成AAC。

一、准备工作

开发环境

jdk1.8 

Eclipse Luna Service Release 1 (4.4.1)

运行环境:

华为荣耀6(Android4.4)、华为p9(Android7.0)

二、程序实现

代码截图如下:

基于FFmpeg的音频编码(PCM数据编码成AAC android)_第1张图片

该demo依赖v7包。

FFAacEncoderDemo工程src目录

  • MainActivity.java是主界面,用来控制录音开始和结束。

  • FFAacEncoder.java时native方法,用来和jni通信。

jni目录:

  • include目录下是FFmpeg的一些.h文件

  • libs目录下是FFmpeg编译的so

  • AacCoderc 音频编码

  • cn_vn_aacEncoder_jni_FFAacEncoderJni jni代码与java通信。

1 录音(获取pcm数据)

开始录音

private void startRecord(){        Log.i(TAG, "startRecord mIsRecording="+mIsRecording);      if(!mIsRecording){          mIsRecording = true;          synchronized (mLock) {              mAudioRecordGetExit = false;          }          //初始化ffmpeg 编码器          mFFAacEncoderJni.start();          //创建录音线程、开始录音          mAudioRecordGetThread = new Thread(new AudioRecordGet());          mAudioRecordGetThread.start();      }  }

关闭录音

private void stoptRecord(){      if(mIsRecording){          synchronized (mLock) {              mAudioRecordGetExit = true;          }          mIsRecording = false;      }  }

具体录音通过使用AudioRecord

private class AudioRecordGet implements Runnable{      private AudioRecord mAudioRecord;      private static final boolean PCM_DUMP_DEBUG = true;      private static final boolean AAC_DUMP_DEBUG = false;      private int mAudioSource = MediaRecorder.AudioSource.MIC;      //采样频率,采样频率越高,音质越好。44100 、22050、 8000、4000等      private int mSampleRateHz = 8000;      //MONO为单声道 ,STEREO为双声道      private int mChannelConfig = AudioFormat.CHANNEL_IN_MONO;      //编码格式和采样大小,pcm编码;支持的采样大小16bit和8bit,采样大小越大,信息越多,音质越好。      private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;      //该size设置为AudioRecord.getMinBufferSize(mSampleRateHz, mChannelConfig, mAudioFormat); 编码aac时会失败。      private int mBufferSizeInBytes = 2048;//AudioRecord.getMinBufferSize(mSampleRateHz, mChannelConfig, mAudioFormat);      private AudioPCMData mAudioPCMData;      public AudioRecordGet() {          Log.i(TAG, "AudioRecordGet ");          mAudioPCMData = new AudioPCMData(mBufferSizeInBytes);          mAudioRecord = new AudioRecord(mAudioSource,                  mSampleRateHz, mChannelConfig, mAudioFormat, mBufferSizeInBytes);          Log.i(TAG,"mBufferSizeInBytes="+mBufferSizeInBytes);      }      @Override      public void run() {          mAudioRecord.startRecording();          FileOutputStream outPCM = null;          try {              if (PCM_DUMP_DEBUG) {                  String File = "/sdcard/test.pcm";                  outPCM = new FileOutputStream(File);              }          } catch (Exception e) {              e.printStackTrace();          }          for(;;){              synchronized (mLock) {                  if(mAudioRecordGetExit){                      break;                  }              }              //读取录音数据              int readSize = mAudioRecord.read(mAudioPCMData.mData, 0, mBufferSizeInBytes);              if (AudioRecord.ERROR_INVALID_OPERATION != readSize) {                  if (PCM_DUMP_DEBUG && null != outPCM) {                      try {                          outPCM.write(mAudioPCMData.mData, 0, readSize);                      } catch (Exception e) {                          e.printStackTrace();                      }                  }                  mAudioPCMData.mFrameSize = readSize;                  Log.i(TAG, "audio pcm size="+readSize);                  //设置pcm数据,进行aac编码                  mFFAacEncoderJni.setPcmData(mAudioPCMData.mData, readSize);              }          }          if(PCM_DUMP_DEBUG && null != outPCM){              try {                  outPCM.close();              } catch (IOException e) {                  e.printStackTrace();              }          }          //停止录音、释放          mAudioRecord.stop();          mAudioRecord.release();          //停止音频编码          mFFAacEncoderJni.stop();          Log.i(TAG,"AudioRecordGet thread exit success");      }         }

2 PCM编码成AAC

1 初始化编码器

public class FFAacEncoder {      private String TAG = "FFAacEncoder java";      //load .so      static{          System.loadLibrary("avcodec-57");          System.loadLibrary("avdevice-57");          System.loadLibrary("avfilter-6");          System.loadLibrary("avformat-57");          System.loadLibrary("avutil-55");          System.loadLibrary("postproc-54");          System.loadLibrary("swresample-2");          System.loadLibrary("swscale-4");          System.loadLibrary("aacEncoder");      }            private int mNativeContext = 0;      //初始化编码器      private native final void nativeStart();      //对pcm数据进行编码      private native final void nativeSetPcmData(byte[] pcm, int len);      //必要的清理      private native final void nativeStop();            public void start(){          nativeStart();      }            public void setPcmData(byte[] pcm, int len){          nativeSetPcmData(pcm, len);      }            public void stop(){          nativeStop();      }  }

调用nativeStart方法。


2 音频编码

//设置pcm数据,进行aac编码  mFFAacEncoderJni.setPcmData(mAudioPCMData.mData, readSize);

调用nativeSetPcmData

C++层代码,通过编码获取的AAC原始数据不同播放(存储在/sdcard/test.aac文件中,不能播放),

需要添加adts header(不懂的可以了解一下AAC格式),这样才可以正常播放。/sdcard/adts.aac该文件添加了header,可以正常播放。

三、运行效果

运行效果:

基于FFmpeg的音频编码(PCM数据编码成AAC android)_第2张图片

运行结果将生成文件 /sdcard/test.aac

基于FFmpeg的音频编码(PCM数据编码成AAC android)_第3张图片

四、其他补充

博客地址:http://blog.csdn.net/vnanyesheshou/article/details/54560684

注:本文著作权归作者,由demo大师(http://www.demodashi.com)宣传,拒绝转载,转载需要作者授权


更多相关文章

  1. Android利用JDBC连接服务器数据库
  2. Android 本地数据存储 API(二)
  3. Android 数据存储四种方式
  4. 赵雅智_使用sqlite创建数据库
  5. Android音频系统之AudioTrack
  6. Android 使用ContentProvider(内容提供者)共享数据
  7. Android中的数据结构

随机推荐

  1. android 手电筒
  2. Android中获取和设置手机的壁纸
  3. Android(安卓)http文件上传-本地+服务器
  4. android 多个activity 共用一套广播时,写
  5. Android(安卓)优化
  6. Android获取手机的型号和系统版本
  7. Android.StructureOfAndroidSourceCodeRo
  8. Android(安卓)创建与解析XML(三)—— Sax方
  9. Timer和TimerTask的知识点
  10. Android获取sdcard信息