Android音視頻-音頻採集

Android的音視頻開發是我暫定的一個職業發展的一個方向,通過自學記錄一些記了又忘記的知識。

音頻基礎知識

  • 採樣率(samplerate)


    這裏寫圖片描述

    藍色代表模擬音頻信號,紅色的點代表採樣得到的量化數值。

    採用就是把模擬信號數字化的過程,不僅僅是音頻需要採樣,所有的模擬信號都需要通過採樣轉換爲可以用0101來表示的數字信號。常用的音頻採樣頻率有:8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz、96kHz、192kHz等。

    • 人耳可以聽到的聲波頻率範圍?
      20-20000Hz。爲了保證聲音不失真,採樣頻率應在40kHz以上。

AudioRecord構造參數中的sampleRateInHz。

  • 量化精度(位寬)
    上圖中,每一個紅色的採樣點,都需要用一個數值來表示大小,這個數值的數據類型大小可以是:4bit、8bit、16bit、32bit等等,位數越多,表示得就越精細,聲音質量自然就越好,當然,數據量也會成倍增大。
    AudioRecord構造參數中的audioFormat。

  • 聲道數(channels)
    由於音頻的採集和播放是可以疊加的,因此,可以同時從多個音頻源採集聲音,並分別輸出到不同的揚聲器,故聲道數一般表示聲音錄製時的音源數量或回放時相應的揚聲器數量。
    AudioRecord 構造參數中的channelConfig。

  • 音頻幀(frame)
    視頻我們知道每一幀是一張圖片,音頻數據是流式的,沒有明確的一幀幀的概念,但是在音頻處理的時候,一般取2.5ms-60ms爲單位數據量的一幀音頻。
    假設某通道音頻信號採樣率爲8kHz,位寬位16bit,20ms一幀,雙通道,那麼一幀音頻的大小爲:
    8000*16bit*0.02*2=5120bit=640byte

  • 音頻編碼
    是將音頻採樣數據(PCM等)壓縮成爲音頻碼流,從而降低音頻的數據量。模擬的音頻信號轉換爲數字信號需要經過採樣和量化,量化的過程被稱之爲編碼,根據不同的量化策略,產生了許多不同的編碼方式,常見的編碼方式有:PCM 和 ADPCM

  • 爲什麼要音頻編碼
    存儲一秒鐘採樣率爲44.1KHz,位深爲16bit,雙聲道的PCM編碼的音頻信號,需要
    44100*16bit*2 / 8/1024 = 172.2KB的空間,那麼1分鐘則約爲10.09M。
    這對大部分用戶是不可接受的。
    只有2種方法,降低採樣指標或者壓縮。

    • 音頻壓縮
      降低採樣是不可取的,因此就有了各種各樣的壓縮方式。
      有兩類主要的音頻文件格式:
      有損文件格式: 是基於聲學心理學的模型,除去人類很難或根本聽不到的聲音。
      無損格式,例如PCM,WAV,ALS,ALAC,TAK,FLAC,APE,WavPack(WV)
      有損格式,例如MP3,AAC,WMA,Ogg。
      根據採樣率和採樣大小可以得知,相對自然界的信號,音頻編碼最多隻能做到無限接近,至少目前的技術只能這樣了,相對自然界的信號,任何數字音頻編碼方案都是有損的,因爲無法完全還原。在計算機應用中,能夠達到最高保真水平的就是PCM編碼,被廣泛用於素材保存及音樂欣賞,CD、DVD以及我們常見的WAV文件中均有應用。因此,PCM約定俗成了無損編碼,因爲PCM代表了數字音頻中最佳的保真水準,並不意味着PCM就能夠確保信號絕對保真,PCM也只能做到最大程度的無限接近。
      我們而習慣性的把MP3列入有損音頻編碼範疇,是相對PCM編碼的。

Android如何採集音頻

Android SDK對於音頻採集提供兩套API:MediaRecorder和AudioRecorder,前者是偏上層的一個API,可以直接把手機麥克風錄入的音頻數據進行編碼壓縮爲AMR,MP3等並保存文件。後者接近底層,可以靈活控制,得到原始的一幀幀PCM音頻數據。
當要簡單的把數據採集爲音頻文件,就使用MediaRecorder,如果要對音頻做進一步的算法處理就使用AudioRecorder。

  • 什麼是PCM音頻數據?
  • PCM(Pulse Code Modulation)也被稱爲脈衝編碼調製。PCM音頻數據是未經壓縮的音頻採樣數據裸流,它是由模擬信號經過採樣、量化、編碼轉換成的標準的數字音頻數據。(詳細參考

AudioRecord

簡介

AudioRecord輸出是PCM語音數據,如果保存成音頻文件,是不能夠被播放器播放的,所以必須先寫代碼實現數據編碼以及壓縮。

AudioRecord適用於對採集的音頻數據進行二次處理的,我們首先看到代碼AudioRecord類的構造函數。

/**
     * Class constructor.
     * Though some invalid parameters will result in an {@link IllegalArgumentException} exception,
     * other errors do not.  Thus you should call {@link #getState()} immediately after construction
     * to confirm that the object is usable.
     * @param audioSource the recording source.
     *   See {@link MediaRecorder.AudioSource} for the recording source definitions.
     * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
     *   rate that is guaranteed to work on all devices, but other rates such as 22050,
     *   16000, and 11025 may work on some devices.
     *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
     *   which is usually the sample rate of the source.
     *   {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
     * @param channelConfig describes the configuration of the audio channels.
     *   See {@link AudioFormat#CHANNEL_IN_MONO} and
     *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
     *   to work on all devices.
     * @param audioFormat the format in which the audio data is to be returned.
     *   See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
     * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
     *   to during the recording. New audio data can be read from this buffer in smaller chunks
     *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
     *   required buffer size for the successful creation of an AudioRecord instance. Using values
     *   smaller than getMinBufferSize() will result in an initialization failure.
     * @throws java.lang.IllegalArgumentException
     */
    public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes)

看這個構造函數的參數的解釋可以明白個七七八八。具體的介紹如下:

  • audioSource

音頻採集的輸入源,可選的值以常量的形式定義在 MediaRecorder.AudioSource 類中,常用的值包括:DEFAULT(默認),VOICE_RECOGNITION(用於語音識別,等同於DEFAULT),MIC(由手機麥克風輸入),VOICE_COMMUNICATION(用於VoIP應用)等等。

  • sampleRateInHz

採樣率,注意,目前44100Hz是唯一可以保證兼容所有Android手機的採樣率。

  • channelConfig

通道數的配置,可選的值以常量的形式定義在 AudioFormat 類中,常用的是 CHANNEL_IN_MONO(單通道),CHANNEL_IN_STEREO(雙通道)

  • audioFormat

這個參數是用來配置“數據位寬”的,可選的值也是以常量的形式定義在 AudioFormat 類中,常用的是 ENCODING_PCM_16BIT(16bit),ENCODING_PCM_8BIT(8bit),注意,前者是可以保證兼容所有Android手機的。

  • bufferSizeInBytes

配置的是 AudioRecord 內部的音頻緩衝區的大小,該緩衝區的值不能低於一幀“音頻幀”(Frame)的大小,而前一篇文章介紹過,一幀音頻幀的大小計算如下:
int size = 採樣率 x 位寬 x 採樣時間 x 通道數

在Android開發中,AudioRecord 類提供了一個幫助你確定這個 bufferSizeInBytes 的函數,原型如下:

int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);

不同的廠商的底層實現是不一樣的,但無外乎就是根據上面的計算公式得到一幀的大小,音頻緩衝區的大小則必須是一幀大小的2~N倍。

使用AudioRecord

操作AudioRecord步驟如下:

  1. 配置參數,初始化AudioRecord構造函數
  2. 開始採集
  3. 開啓一個子線程,不斷從AudioRecord的緩衝區將音頻數據讀出來。注意,這個過程一定要及時,否則就會出現“overrun”的錯誤,該錯誤在音頻開發中比較常見,意味着應用層沒有及時地取走音頻數據,導致內部的音頻緩衝區溢出。
  4. 停止採集,釋放資源。

示例代碼:
注意添加RECORD_AUDIO權限。
點擊查看

MediaRecorder

MediaRecorder可以直接把手機麥克風錄入的音頻數據進行編碼壓縮爲AMR,MP3等並保存文件。

使用MediaRecorder

簡單操作使用MediaRecorder類步驟如下:

  1. 實例化MediaRecorder對象
  2. 使用函數SetAudioSource設置硬件設備爲採集音頻輸入數據
  3. 使用函數SetOutputFormat設置輸出音頻格式。使用類OutputFormat列出支持的輸出格式
  4. 調用方法SetAudioEncoder方法設置音頻編碼格式
  5. 調用SetOutputFile方法保存輸出文件數據的絕對完整路徑
  6. 調用Prepare方法初始化錄製
  7. 調用Start方法開始錄製

示例代碼:
注意添加權限:
WRITE_EXTERNAL_STORAGE;
RECORD_AUDIO;
點擊查看

總結

  • MediaRecorder和AudioRecord都可以錄製音頻,區別是MediaRecorder錄製的音頻文件是經過壓縮後的,需要設置編碼器。並且錄製的音頻文件可以用系統自帶的Music播放器播放。
  • 而AudioRecord錄製的是PCM格式的音頻文件,需要用AudioTrack來播放,AudioTrack更接近底層。

  • 在用MediaRecorder進行錄製音視頻時,最終還是會創建AudioRecord用來與AudioFlinger進行交互。

  • C++層MediaRecorder創建AudioRecord類的代碼位於AudioSource類構造函數中.

  • MediaRecorder錄製的數據是 amr MP3 格式;AudioRecorder錄製出來的是比較原始的PCM音頻格式;PCM經過編碼壓縮可以爲 amr MP3 AAC。

  • 優缺點:

    • AudioRecord
      主要是實現邊錄邊播以及對音頻的實時處理,這個特性讓他更適合在語音方面有優勢;
      優點:語音的實時處理,可以用代碼實現各種音頻的封裝
      缺點:輸出是PCM格式文件,如果保存成音頻文件,是不能夠被播放器播放的,所以必須先寫代碼實現數據編碼以及壓縮
    • MediaRecorder
      已經集成了錄音、編碼、壓縮等,支持少量的錄音音頻格式,大概有,aac,amr,3gp等
      優點:集成,直接調用相關接口即可,代碼量小
      缺點:無法實時處理音頻;輸出的音頻格式不是很多,例如沒有輸出mp3格式文件
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章