Loading...
墨滴

Javascript

2021/11/08  阅读:28  主题:极简黑

音视频多媒体之音频采集

音视频多媒体之音频采集(Android)

一、音频采集 ?

利用各个平台提供的开放API收集音频数据(包括编码好的音频数据以及原始音频数据PCM).PCM数据格式请参阅读前篇PCM格式你该知道的一切.

二、Android平台音频采集

android平台上的音频采集一般就三种:1.利用android内置的应用程序 2.使用MediaRecorder进行音频捕获 3.使用AudioRecord进行音频捕获。此3种方式的灵活性逐渐增大,相应的所需要做的工作也逐渐增多。

1.使用Android内置的应用程序
Intent intent=new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
startActivityForResult(intent,0); //通过startActivityForResult获取音频录制的结果的路径

    这种方式灵活度最差,一般情况就是做演示用下,开发中基本不使用这种方案.

2.使用MediaRecorder进行音频的捕获

    这种方案相较于调用系统内置的用用程序,灵活度要高很多,便于开发者在UI界面上布局,而且系统封装的很好,便于使用,唯一的缺点是使用它录下来的音频是经过编码的,没有办法的得到原始的音频。同时MediaRecorder即可用于音频的捕获也可以用于视频的捕获相当的强大。实际开发中没有特殊需求的话,用的是比较多的!

    其使用步骤如下,调用如下方法(Ps:调用顺序顺序对结果的影响是非常的大):

MediaRecorder recorder=new MediaRecorder();//创建MediaRecoder对象

1.recorder.setAudioSource(MediaRecorder.AudioSource.MIC); //调用setAudioSource方法 (调用的第一个方法) 
MediaRecorder.AudioSource.CAMCORDER 和 MediaRecorder.AudioSource.VOICE_RECOGNITION当设备具有。>=2个麦克风的时候就可以使用它们。
MediaRecorder.AudioSource.VOICE_CALL从电话中录音

2.recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//setOutputFormat方法(调用的第二个方法)
   MediaRecorder.OutputFormat.THREE_GPP 输出文件将是一个扩展名为(.3gp)的文件。它可能包含音频和视频。
   MediaRecorder.OutputFormat.MPEG_4 输出一个MPEG_4文件,它可能包含音频和视频。

3.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); //setAudioEncoder方法 (这是调用的第三个方法)

4.recorder.setOutputFile(url); //setOutputFile方法 url是目标文件路径(这是调用的第四个方法)

    以上四个方法依次调用完成之后,就可以像MediaPlayer一样控制录制和暂停录制了(其录制的音频数据是编码好的音频数据)

    当然,MediaRecoder还有其他的几个API方法,用于更加精细的控制音频的录制:

//设置录制允许的最大时长 单位是毫秒。必须在setOutFormat方法之后,prepare方法之前使用。
setMaxDuration(int);
//设置文件录制的存放文件的最大值,单位是字节 。必须在setOutFormat方法之后,prepare方法之前使用。 
setMaxFileSize(long)
//允许录制的音频通道数,通常是一个通道(单声道,2个通道双声道,立体声)。必须在调用prepare方法之前调用。
setAudioChannels(int)
//允许制定捕获和编码音频的采样率。硬件和使用的编码器将会决定合适的采样率。必须在调用prepare方法之前调用。
setAudioSamplingRate(int)
//允许指定当压缩音频时编码器所使用的每秒位数(位/秒)。必须在调用prepare方法之前调用。
setAudioEncodingBitRate在(int)

    MediaRecoder这种方案在实际开发中,当你不关心编码的具体环节或者不想写编码器的情况下,是一个比较好的选择.

3.使用AudioRecord 进行音频捕获

这种方法是3种之中最为灵活的,能让开发者最大限度的处理采集的音频,同时它捕获到的音频是原始音频PCM格式的(PCM格式你该知道的一切),像做变声处理的需要就必须要用它收集音频。在实际开发中,它也是最常用来采集音频的手段。也是本文介绍的重点:

//指定音频源 这个和MediaRecorder是相同的 
int audioSource=MediaRecorder.AudioSource.MIC;
//指定采样率 (MediaRecoder 的采样率通常是8000Hz CD的通常是44100Hz 不同的Android手机硬件将能够以不同的采样率进行采样。其中11025是一个常见的采样率)
int sampleRateInHz=11025 ;
//指定捕获音频的通道数目。在AudioFormat类中指定用于此的常量  
int channelConfig=AudioFormat.CHANNEL_CONFIGURATION_MONO;
//指定音频量化位数 ,在AudioFormaat类中指定了以下各种可能的常量。通常我们选择ENCODING_PCM_16BIT和ENCODING_PCM_8BIT PCM代表的是脉冲编码调制,它实际上是原始音频样本。
//因此可以设置每个样本的分辨率为16位或者8位,16位将占用更多的空间和处理能力,表示的音频也更加接近真实。
int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
指定缓冲区大小。调用AudioRecord类的getMinBufferSize方法可以获得。
//创建AudioRecord。AudioRecord类实际上不会保存捕获的音频,因此需要手动创建文件并保存下载。
AudioRecord record=new AudioRecord(audioSource,sampleRateInHz,channelConfig,audioFormat,bufferSizeInBytes); 

其完整的简易调用流程如下:

public class MainActivity extends Activity implements OnClickListener {
 Button startRecordingButton, stopRecordingButton;//开始录音、停止录音
 File recordingFile;//储存AudioRecord录下来的文件
 boolean isRecording = false; //true表示正在录音
 AudioRecord audioRecord=null;
 File parent=null;//文件目录
 int bufferSize=0;//最小缓冲区大小
 int sampleRateInHz = 11025;//采样率
 int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; //单声道
 int audioFormat = AudioFormat.ENCODING_PCM_16BIT; //量化位数
 String TAG="AudioRecord";
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  requestWindowFeature(Window.FEATURE_NO_TITLE);
  setContentView(R.layout.main);
  init();
  initListener();
 }
 
 //初始化
 public void init(){
  startRecordingButton = (Button)findViewById(R.id.StartRecordingButton);
  stopRecordingButton = (Button)findViewById(R.id.StopRecordingButton);
  
  bufferSize = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig, audioFormat);//计算最小缓冲区
  audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRateInHz,channelConfig, audioFormat, bufferSize);//创建AudioRecorder对象
  
  parent = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/AudiioRecordTest");
  if(!parent.exists())
   parent.mkdirs();//创建文件夹
 }
 
    //初始化监听器
 public void initListener(){
  startRecordingButton.setOnClickListener(this);
  stopRecordingButton.setOnClickListener(this);
 }
 
 public void onClick(View v) {
  switch (v.getId()) {
  //开始录音
  case R.id.StartRecordingButton:
  {
   record();
   break;
  }
     
  //停止录音
  case R.id.StopRecordingButton:
  {
   stopRecording();
   break;
  }
 }
  
 }
 
    //开始录音
 public void record() {
  isRecording = true;
  new Thread(new Runnable() {
   @Override
   public void run() {
    isRecording = true;
    
    recordingFile = new File(parent,"audiotest.pcm");
    if(recordingFile.exists()){
     recordingFile.delete();
    }
    
    try {
      recordingFile.createNewFile();
        } 
    catch (IOException e) {
      e.printStackTrace();
      Log.e(TAG,"创建储存音频文件出错");
        }
    
    
    try {
    DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(recordingFile)));
       byte[] buffer = new byte[bufferSize];
    audioRecord.startRecording();//开始录音
     int r = 0;
     while (isRecording) {
      int bufferReadResult = audioRecord.read(buffer,0,bufferSize);
      for (int i = 0; i < bufferReadResult; i++) 
      {
       dos.write(buffer[i]); 
      }
      r++;
     }
     audioRecord.stop();//停止录音
     dos.close();
    } catch (Throwable t) {
     Log.e(TAG, "Recording Failed");
    }
    
   }
  }).start();
 
 }
    
    //停止录音
 public void stopRecording() 
 {
  isRecording = false;
 }
}

获取到PCM数据之后可以使用ffmpeg进行播放,或者可视化的软件进行播放。例如: 原始音频PCM播放器 使用方法 : 文件->导入->裸数据 然后根据你录音时的配置填写相应参数 就可以播放了!

上述代码的完整Demo如下(注意权限): MediaRecorder采集音频的Demo源码 AudioRecord采集音频的Demo源码

至于收集的PCM数据如何进行音频编码,欢迎关注后续的文章以及公众号 CodeEngine

- END -

Javascript

2021/11/08  阅读:28  主题:极简黑

作者介绍

Javascript