因為mp3和aac兩個格式擁有標準的規範定義,比如mp3規定每幀音訊固定包含1152個樣本,而aac規定每幀音訊固定包含1024個樣本。在它們的解碼器例項AVCodecContext中,即可從frame_size欄位獲取每幀音訊的樣本數量。
然而其他音訊格式(如ogg、amr、wma等)的每幀樣本數並不固定,從frame_size欄位取到的樣本數量為0,這不僅導致SDL初始化失敗,還導致重取樣過程異常。為了能夠播放其他格式的音訊,需要對playaudio.c做下列三處修改。
1、從解碼器例項獲取音訊樣本數時,如果發現frame_size為0,就要把樣本數變數設為512(注意該數值必須為2的n次冪,如256、512、1024等),修改後的賦值程式碼如下所示:
2、在遍歷音訊幀的時候,要重新計算實際的取樣位數,以便確定多少音訊資料送給揚聲器。具體的計算過程是這樣的:先呼叫swr_convert函式對音訊重取樣,該函式的返回值為輸出的資料大小;這個輸入大小乘以聲道數量乘以音訊樣本的位深(位深表示每個音訊樣本佔據幾個位元組),最終的乘積便是要送給揚聲器的音訊資料大小。詳細的計算程式碼如下所示:
3、SDL的音訊回撥函式當中,注意每次要湊足len個位元組。鑑於重取樣後的音訊資料可能較大(主要是amr格式有這種情況),因此要按照len指定的長度切割資料,確保每次回撥函式都剛好把長度為len的音訊資料送往揚聲器。修改後的回撥程式碼如下所示:
上述修改後的程式碼已經附在了《FFmpeg開發實戰:從零基礎到短影片上線》一書第10章的原始碼chapter10/playaudio2.c,這個c程式碼是playaudio.c的改進版,除了支援原來mp3和aac格式的音訊播放,還支援ogg、amr、wma等格式的音訊播放,以及asf、webm等影片檔案的音訊播放。
接著執行下面的編譯命令。
編譯完成後執行以下命令啟動測試程式,期望播放音訊檔案ring.ogg。
程式執行完畢,發現控制檯輸出以下的日誌資訊。
同時電腦揚聲器傳來了兩個“叮咚”的鈴聲,表示上述程式碼正確實現了播放ogg音訊的功能。