解決AAC音頻編碼時間戳的計算問題

原文地址 原創文章,轉載請聯繫作者

西北望鄉何處是,東南見月幾回圓。
昨風一吹無人會,今夜清光似往年。

主題

音頻是流式數據,並不像視頻一樣有P幀和B幀的概念。就像砌牆一樣,咔咔往上摞就行了。一般來說,AAC編碼中生成文件這一步,如果使用的是OutputStream流寫入文件的話,就完全不需要計算時間。但在音視頻同步或者使用Android自帶的MediaMuxer來生成音頻文件時,就需要計算音頻幀的時間戳。

參考

本文所涉及到的計算方法和API,爲在Android環境下。使用AudioRecord音頻錄製,MediaCodeC編碼AAC格式音頻,同時使用MediaMuxer封裝AAC格式音頻文件。

方法

AAC編碼有兩種計算時間戳的方式。第一種:使用PCM的數據量來計算;第二種:計算出AAC編碼相應參數配置下,一幀的持續時間,再配合幀數來計算。

AAC編碼、MediaMuxer生成文件僞代碼

MediaCodeC的AAC編碼流程不再贅述,這裏用僞代碼來代替。主要是爲了體現在代碼何處設置時間戳:

// MediaCodeC獲得可用輸入隊列
index = codeC.dequeueInputBuffer(......)
// 當獲取到可用輸出隊列時,我們將獲取的PCM數據填入
inputBuffer = codec.getInputBuffer(index)
// 將PCM數據(ByteArray)填充到InputBuffer
inputBuffer.put(byteAarray——PCM數據)
codec.queueInputBuffer(index, 0, byteArray的size
                            , presentationTimeUs, 0)
複製代碼

在以上的僞代碼中,presentationTimeUs就是需要我們設置時間戳的地方

填充PCM數據後,在得到MediaCodeC輸出後,使用MedaMuxer寫入數據,生成AAC文件。

path = 輸出路徑。後綴aac、或者mp4
mediaMuxer= MediaMuxer(path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)

mediaMuxer.addTrack(音頻軌)
mediaMuxer.start()

// codec拿到可用的輸出數據。這些數據就是AAC格式的音頻數據
id = codec.dequeueOutputBuffer(bufferInfo, 10000)
if(id >= 0){
    outputBuffer = codec.getOutputBuffer(id)
    mediaMuxer.writeSamplet(audioTrack, outputBuffer, bufferInfo)   
}

複製代碼

需要注意的是:使用MediaMuxer生成AAC音頻文件時,不需要添加AAC頭信息,直接寫入即可。
MediaMuxer寫入文件時,BufferInfo這個參數就包含了這一幀數據的偏移、以及時間戳等信息。

更加完整的音頻編碼代碼,請參考GitHub地址AudioEncoder

使用PCM的數據量來計算

PCM是沒有經過壓縮的純音頻數據,我之前寫過一篇音頻入門的文章初識音頻,記錄了一些PCM相關的常識問題,感興趣的可以去看看。
PCM作爲最原始的音頻數據,可以根據大小來計算出時間,先給出公式:

presentationTimeUs = 1000000L * (totalBytes / 2) / sampleRate
複製代碼

這是配置爲採樣率sampletRate、採樣位數爲16bit、單聲道的PCM文件時間戳計算方式

接下來我們來分析以上公式的計算由來:
假設有一段PCM文件,採樣率爲S,採樣位數爲n--(一般 採樣位數的選擇有4bit、8bit、16bit、32bit),聲道爲單聲道。那麼在1s內,這段PCM的大小爲:

size = S * n * 1,單位爲bit

複製代碼

衆所周知,1 Byte = 8bit, 1 Short = 16bit。那麼單位時間內,PCM的大小爲:

以byte爲單位 = S * n * 1 / 8
以short爲單位  = S * n * 1 / 16

複製代碼

那麼根據以上就可得到,配置參數爲採樣率sampleRate、16bit、聲道爲1的PCM文件,當傳入編碼器的總大小達到totalByte時,時間戳的計算方式:

currents (微妙) = totalByte / (sampleRate * 16 * 1 / 8)
 = totalByte / 2 / sampleRate * 1000000L 

複製代碼

當然如果選擇以ShortArray來承載PCM數據的話,那麼公式則變爲:

currents (微妙) = totalShort / (sampleRate * 16 * 1 / 16)
 = totalShort / sampletRate * 1000000L
複製代碼

使用AAC幀時間計算

當編碼器每輸出一次數據,即可視作輸出一幀AAC數據。一幀AAC原始數據包括1024個sample,那麼AAC音頻文件1s內的幀數爲:sampleRate / 1024 幀。從而得到一幀AAC的持續時間爲:

perFrameTime (微妙) = 1000000L / sampleRate / 1024

複製代碼

已知每一幀的持續時間的話,那麼只需要根據當前幀數,即可計算出當前的時間戳。

以上

轉載於:https://juejin.im/post/5d0af54be51d4577770e7398

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章