天天看點

直播間源碼開發音視訊入門之音頻采集、編碼、播放

直播間源碼開發音視訊入門之音頻采集、編碼、播放

今天我們學習音頻的采集、編碼、生成檔案、轉碼等操作,我們生成三種格式的檔案格式,pcm、wav、aac 三種格式,并且我們用 AudioStack 來播放音頻,最後我們播放這個音頻。

本篇文章你将學到:

AudioRecord 音頻的采集

生成 PCM 檔案

PCM 轉化為 WAV 檔案

PCM 轉化為 AAC 檔案

附上正常運作 demo 源碼

AudioRecord 是 Android 系統提供的用于實作錄音的功能類,要想了解這個類的具體的說明和用法,我們可以去看一下官方的文檔:

AndioRecord類的主要功能是讓各種 Java 應用能夠管理音頻資源,以便它們通過此類能夠錄制聲音相關的硬體所收集的聲音。此功能的實作就是通過”pulling”(讀取)AudioRecord對象的聲音資料來完成的。在錄音過程中,應用所需要做的就是通過後面三個類方法中的一個去及時地擷取AudioRecord對象的錄音資料. AudioRecord類提供的三個擷取聲音資料的方法分别是read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int). 無論選擇使用那一個方法都必須事先設定友善使用者的聲音資料的存儲格式。

開始錄音的時候,AudioRecord需要初始化一個相關聯的聲音buffer, 這個buffer主要是用來儲存新的聲音資料。這個buffer的大小,我們可以在對象構造期間去指定。它表明一個AudioRecord對象還沒有被讀取(同步)聲音資料前能錄多長的音(即一次可以錄制的聲音容量)。聲音資料從音頻硬體中被讀出,資料大小不超過整個錄音資料的大小(可以分多次讀出),即每次讀取初始化buffer容量的資料。

1.1 首先要聲明一些全局的變量和常量參數

主要是聲明一些用到的參數,具體解釋可以看注釋。

1.2 擷取buffer的大小并建立AudioRecord

1.3 建立一個子線程開啟線程錄音,并寫入檔案檔案

1.4 權限和采集小結

注意:權限需求:WRITE_EXTERNAL_STORAGE、RECORD_AUDIO

到現在基本的錄音的流程就介紹完了,但是這時候問題來了:

1) 我按照流程,把音頻資料都輸出到檔案裡面了,停止錄音後,打開此檔案,發現不能播放,到底是為什麼呢?

答:按照流程走完了,資料是進去了,但是現在的檔案裡面的内容僅僅是最原始的音頻資料,術語稱為raw(中文解釋是“原材料”或“未經處理的東西”),這時候,你讓播放器去打開,它既不知道儲存的格式是什麼,又不知道如何進行解碼操作。當然播放不了。

2) 那如何才能在播放器中播放我錄制的内容呢?

答: 在檔案的資料開頭加入AAC HEAD 或者 AAC 資料即可,也就是檔案頭。隻有加上檔案頭部的資料,播放器才能正确的知道裡面的内容到底是什麼,進而能夠正常的解析并播放裡面的内容。

我這裡簡單的介紹一下這三種的格式的基本介紹,具體我添加了具體的通路連結,具體點選詳情檢視,我這裡點到為止。

PCM:PCM(Pulse Code Modulation----脈碼調制錄音)。所謂PCM錄音就是将聲音等模拟信号變成符号化的脈沖列,再予以記錄。PCM信号是由[1]、[0]等符号構成的數字信号,而未經過任何編碼和壓縮處理。與模拟信号比,它不易受傳送系統的雜波及失真的影響。動态範圍寬,可得到音質相當好的影響效果。

WAV : wav是一種無損的音頻檔案格式,WAV符合 PIFF(Resource Interchange File Format)規範。所有的WAV都有一個檔案頭,這個檔案頭音頻流的編碼參數。WAV對音頻流的編碼沒有硬性規定,除了PCM之外,還有幾乎所有支援ACM規範的編碼都可以為WAV的音頻流進行編碼。

簡單來說:WAV 是一種無損的音頻檔案格式,PCM是沒有壓縮的編碼方式

AAC : AAC(Advanced Audio Coding),中文稱為“進階音頻編碼”,出現于1997年,基于 MPEG-2的音頻編碼技術。由Fraunhofer IIS、杜比實驗室、AT&T、Sony(索尼)等公司共同開發,目的是取代MP3格式。2000年,MPEG-4标準出現後,AAC 重新內建了其特性,加入了SBR技術和PS技術,為了差別于傳統的 MPEG-2 AAC 又稱為 MPEG-4 AAC。他是一種專為聲音資料設計的檔案壓縮格式,與Mp3類似。利用AAC格式,可使聲音檔案明顯減小,而不會讓人感覺聲音品質有所降低 。

在檔案的資料開頭加入WAVE HEAD 或者 AAC 資料即可,也就是檔案頭。隻有加上檔案頭部的資料,播放器才能正确的知道裡面的内容到底是什麼,進而能夠正常的解析并播放裡面的内容。具體的頭檔案的描述,在Play a WAV file on an AudioTrack裡面可以進行了解。

看到下圖我們生成了相對的 wav 檔案,我們用用本機自帶播放器打開此時就能正常播放,但是我們發現他的大小比較大,我們看到就是幾分鐘就這麼大,我們平時用的是 mp3 、aac 格式的,我們如何辦到的呢,這裡我們繼續看一下 mp3 格式如何能生成 。

生成 aac 檔案播放

AudioTrack 類可以完成Android平台上音頻資料的輸出任務。AudioTrack有兩種資料加載模式(MODE_STREAM和MODE_STATIC),對應的是資料加載模式和音頻流類型, 對應着兩種完全不同的使用場景。

MODE_STREAM:在這種模式下,通過write一次次把音頻資料寫到AudioTrack中。這和平時通過write系統調用往檔案中寫資料類似,但這種工作方式每次都需要把資料從使用者提供的Buffer中拷貝到AudioTrack内部的Buffer中,這在一定程度上會使引入延時。為解決這一問題,AudioTrack就引入了第二種模式。

MODE_STATIC:這種模式下,在play之前隻需要把所有資料通過一次write調用傳遞到AudioTrack中的内部緩沖區,後續就不必再傳遞資料了。這種模式适用于像鈴聲這種記憶體占用量較小,延時要求較高的檔案。但它也有一個缺點,就是一次write的資料不能太多,否則系統無法配置設定足夠的記憶體來存儲全部資料。

播放聲音可以用MediaPlayer和AudioTrack,兩者都提供了Java API供應用開發者使用。雖然都可以播放聲音,但兩者還是有很大的差別的,其中最大的差別是MediaPlayer可以播放多種格式的聲音檔案,例如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer會在framework層建立對應的音頻解碼器。而AudioTrack隻能播放已經解碼的PCM流,如果對比支援的檔案格式的話則是AudioTrack隻支援wav格式的音頻檔案,因為wav格式的音頻檔案大部分都是PCM流。AudioTrack不建立解碼器,是以隻能播放不需要解碼的wav檔案。

3.1 音頻流的類型

在AudioTrack構造函數中,會接觸到AudioManager.STREAM_MUSIC這個參數。它的含義與Android系統對音頻流的管理和分類有關。

Android将系統的聲音分為好幾種流類型,下面是幾個常見的:

STREAM_ALARM:警告聲

STREAM_MUSIC:音樂聲,例如music等

STREAM_RING:鈴聲

STREAM_SYSTEM:系統聲音,例如低電提示音,鎖屏音等

STREAM_VOCIE_CALL:通話聲

注意:上面這些類型的劃分和音頻資料本身并沒有關系。例如MUSIC和RING類型都可以是某首MP3歌曲。另外,聲音流類型的選擇沒有固定的标準,例如,鈴聲預覽中的鈴聲可以設定為MUSIC類型。音頻流類型的劃分和Audio系統對音頻的管理政策有關。

3.2 Buffer配置設定和Frame的概念

在計算Buffer配置設定的大小的時候,我們經常用到的一個方法就是:getMinBufferSize。這個函數決定了應用層配置設定多大的資料Buffer。

從AudioTrack.getMinBufferSize開始追溯代碼,可以發現在底層的代碼中有一個很重要的概念:Frame(幀)。Frame是一個機關,用來描述資料量的多少。1機關的Frame等于1個采樣點的位元組數×聲道數(比如PCM16,雙聲道的1個Frame等于2×2=4位元組)。1個采樣點隻針對一個聲道,而實際上可能會有一或多個聲道。由于不能用一個獨立的機關來表示全部聲道一次采樣的資料量,也就引出了Frame的概念。Frame的大小,就是一個采樣點的位元組數×聲道數。另外,在目前的聲霸卡驅動程式中,其内部緩沖區也是采用Frame作為機關來配置設定和管理的。

getMinBufSize會綜合考慮硬體的情況(諸如是否支援采樣率,硬體本身的延遲情況等)後,得出一個最小緩沖區的大小。一般我們配置設定的緩沖大小會是它的整數倍。

3.3 建構過程

每一個音頻流對應着一個AudioTrack類的一個執行個體,每個AudioTrack會在建立時注冊到 AudioFlinger中,由AudioFlinger把所有的AudioTrack進行混合(Mixer),然後輸送到AudioHardware中進行播放,目前Android同時最多可以建立32個音頻流,也就是說,Mixer最多會同時處理32個AudioTrack的資料流。

3.4 Show Me The Code