音視頻開發基礎理論-音頻篇

使用AVFoundation處理視頻
使用AVAssetReader、AVAssetWriter編解碼視頻

之前的兩篇文章淺略講了iOS音視頻開發相關代碼實現;
在編碼時關於音視頻的相關參數比較多,這些參數不是隨便什麼數值就能行的;如果不理解緣由,而填寫了不合適的參數,容易導致音視頻處理過程中出現各種奇怪的問題;
只有明白了音視頻相關的原理,才能理解各種參數的含義,才能更好的實現開發;

現在,就從音頻入手,總結下音頻相關的理論知識;

聲音的本質

聲音是如何產生的?

聲音是由物體振動而產生的,一切正在發聲的物體都在振動

當小球撞擊到音叉的時候,音叉會發生振動,對周圍的空氣產生擠壓,然後導致更大範圍的空氣跟着一起振動,最後我們耳朵旁邊的空氣也開始振動;這是因爲空氣產生了疏密變化,形成疏密相間的縱波,由此就產生了聲波,聲波一直延續到振動消失爲止; 聲波一直傳入我們耳朵,就聽到了聲音;
我們說話時的聲音,也是聲帶振動的結果;
聲音的本質就是聲波;

我們聽到聲音的過程:
聲波 --> 耳廓(收集聲波)--> 外耳道(傳遞聲波) --> 鼓膜(將聲波轉換成振動) --> 聽小骨(放大振動) --> 耳蝸(將振動轉換成電信號) --> 聽覺神經(傳遞電信號) --> 大腦(形成聽覺)

聲波的三要素

聲波的三要素是頻率、振幅和波形;頻率代表音階的高低,振幅代表響度,波形代表音色。

橫座標爲時間,縱座標爲受振動的物體分子來回振動產生的位移;隨着時間推移,分子的來回振動的軌跡,就是一個正弦或餘弦函數的波形圖;

頻率

受振動的物體分子每秒來回振動的次數,叫做頻率;單位是秒分之一(1/s),也稱爲赫茲(Hz);頻率用來表示振動的快慢
(如441Hz代表每秒來回振動441次)

頻率越高,波長就越短。反之頻率越低波長則越長,低頻率可以更容易地繞過障礙物,因此能量衰減就小,聲音就會傳得更遠。

人類耳朵的聽力有一個頻率範圍,大約是20Hz~20kHz,不過,即使是在這個頻率範圍內,不同的頻率,聽力的感覺也會不一樣

振幅

物體未受到振動影響時的位置(橫軸上)稱爲平衡位置;
從平衡位置到最大位移位置之間的距離,就叫做振幅
振幅代表響度,振幅越大表示響度越大能量越大,我們聽到的聲音就越大;

波形

上面我們說聲波是正弦或餘弦函數的圖;但這是在單一頻率的聲波的情況下的;
事實上,聲源的振動產生的並不是單一頻率的聲波,而是由基音和不同頻率的泛音組成的複合聲音;當聲源的主體振動時會發出一個基音;同時其餘各部分也有複合的聲源,這些聲源組合產生泛音(其實就是物理學上的諧波)
泛音決定了不同的音色,不同的聲源由於其材料、結構不同,泛音不同,則發出聲音的音色也不同;

最後用一張圖總結三要素

音頻數字化

上面講到聲音的本質是聲波的形式,聲音屬於模擬信號,但便於計算機處理和存儲的是數字信號;所以需要將模擬信號(轉成數字信號後進行存儲。這一過程,即爲音頻數字化。
我們在互聯網上聽到的聲音,都是先經過錄制後轉爲了數字音頻,再傳輸到互聯網上的;

音頻數字化的常見技術方案是脈衝編碼調製(PCM,Pulse Code Modulation);
主要過程:採樣 、量化 、編碼。

採樣

所謂採樣就是 在時間軸上對信號進行數字化

模擬信號的波形是無限光滑的,可以看成由無數個點組成,由於存儲空間是相對有限的,數字編碼過程中,必須要對波形的點進行採樣。採樣就是每隔一段時間採集一次模擬信號的樣本,在時間上將模擬信號離散化的過程。

根據採樣定理(奈奎斯特–香農採樣定理),只有當採樣率高於聲音信號最高頻率的2倍時,才能把採集的聲音信號唯一地還原成原來的聲音;因此要按比聲音最高頻率高2倍以上的頻率對聲音進行採樣;人耳能夠聽到的頻率範圍是20Hz~20kHz,所以採樣頻率一般爲 44.1kHz,這樣就可以保證採樣聲音達到20kHz也能被數字化,從而使得經過數字化處理之後,人耳聽到的聲音質量不會被降低。採樣率表示每秒採集的樣本數量,44.1kHz就是代表1秒會採樣44100次;

量化

量化是指在幅度軸上對信號進行數字化,將每一個採樣點的樣本值數字化

比如用16比特的二進制信號來表示聲音的一個採樣,而16比特所表示的 範圍是[-32768,32767],共有2^16=625536個可能取值,因此最終模擬的音頻信號在幅度上也分爲了65536層

這裏的16bit即爲位深度(採樣精度/採樣大小):使用多少個二進制位來存儲一個採樣點的樣本值;位深度越高,表示的振幅越精確;

編碼

所謂編碼,就是按照一定的格式記錄採樣和量化後的數字數據,比如順序存儲或壓縮存儲,等等。

編碼涉及了很多種格式,通常說的音頻裸數據格式就是PCM(脈衝編碼調製)數據。PCM需要以下幾個概念:採樣格式(sampleFormat)採樣率 (sampleRate)聲道數(channel)

採樣格式:包含採樣位深度、大小端模式、數據排列方式等;
以FFmpeg定義的sampleFormat爲例:

enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16,         ///< signed 16 bits
    AV_SAMPLE_FMT_S32,         ///< signed 32 bits
    AV_SAMPLE_FMT_FLT,         ///< float
    AV_SAMPLE_FMT_DBL,         ///< double
    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP,        ///< float, planar
    AV_SAMPLE_FMT_DBLP,        ///< double, planar
    AV_SAMPLE_FMT_S64,         ///< signed 64 bits
    AV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar
    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};�����������������

其中U,S,F,D表示存儲的類型,對應unsigned、signed、float和double類型;
數值表示位深度;
P表示聲道數據排列方式爲Planar,還有排列方式爲Packed
對於雙聲道音頻來說,Packed表示兩個聲道的數據交錯存儲,交織在一起,即:
LRLRLRLR 的存儲方式;
Planar 表示兩個聲道分開存儲,也就是平鋪分開,即:
LLLLRRRR 的存儲方式;
以Packed存儲方式爲例 大端模式不同位深度數據存儲如下:

聲道:單聲道產生一組聲波數據,雙聲道(立體聲)產生兩組聲波數據。
對於聲音格式,還有一個概念用來描述它的大小,稱爲比特率(byteRate),即指單位時間內傳輸或處理的比特數量;單位是:比特每秒(bps),還有:千比特每秒(Kbps)、兆比特每秒(Mbps)等等;

以CD的音質爲例:位深度爲16比特(2字節),採樣率爲44.1kHZ,聲道數爲2,這些信息就描述了CD的音質。對於1分鐘CD音質的數據,比特率爲:

44100 * 16 * 2 = 1378.125 Kbps

存儲空間爲:

1378.125 * 60 / 8 / 1024 = 10.09MB

通常,採樣率、位深度越高,數字化音頻的質量就越好。從比特率的特性可以看得出來:比特率越高,數字化音頻的質量也越好;我們所說的無損音樂,就是採樣率、位深度都很高的,沒有進行壓縮處理的數字化聲音;

最後還是用一張圖總結數字化過程:

音頻編解碼

編碼

前面計算了每分鐘CD音質的數據採樣格式,需要的存儲空間約爲10.1MB;在網絡中傳播的話,數據量太大了;
爲了更便於存儲和傳輸,一般都會使用某種音頻編碼對它進行編碼壓縮,然後再存成某種音頻文件格式。

壓縮分爲無損壓縮和有損壓縮。
無損壓縮:解壓後可以完全還原出原始數據;
有損壓縮:解壓後不能完全還原出原始數據,會丟失一部分信息;一般是壓縮掉冗餘信號(冗餘信號是指不能被人耳感知到的信號,包含人耳聽覺範圍之外的音頻信號以及被掩蔽掉的音頻信號等),不進行編碼處理。

解碼

當需要播放音頻時,得先解碼(解壓縮)出PCM數據,然後再進行播放。

常見的編碼格式:

WAV編碼
WAV(Waveform Audio File Format),是由IBM和Microsoft開發的音頻文件格式,擴展名是.wav,通常採用PCM編碼,常用於Windows系統中;編碼的一種實現就是在PCM數據格式的前面加上44字節,分別用來描述PCM的採樣率、聲道數、數據格式等信息。

  • 特點:音質非常好,大量軟件都支持。
  • 適用場合:多媒體開發的中間文件、保存音樂和音效素材。

MP3編碼
MP3(MPEG Audio Layer III)具有不錯的壓縮比,使用LAME編碼的中高碼率的MP3文件,聽感上非常接近源WAV文件。

  • 特點: 壓縮比比較高,大量軟件和硬件都支持,兼容性好。
  • 適用場合:高比特率下對兼容性有要求的音樂欣賞。

AAC編碼
AAC(Advanced Audio Coding)是新一代的音頻有損壓縮技術;

AAC編碼的文件擴展名主要有3種:

  • .acc:傳統的AAC編碼,使用MPEG-2 Audio Transport Stream(ADTS)容器
  • .mp4:使用了MPEG-4 Part 14的簡化版即3GPP Media Release 6 Basic(3gp6)進行封裝的AAC編碼
  • .m4a:爲了區別純音頻MP4文件和包含視頻的MP4文件而由Apple公司使用的擴展名;

  • 特點:在小於128Kbit/s的碼率下表現優異,並且多用於視頻中的音頻編碼。
  • 適用場合:128Kbit/s以下的音頻編碼,多用於視頻中音頻軌的編碼。

代碼實現

  • AVFoundation 音頻編碼
// -----解碼----
// AVAssetReader
do {
    reader = try AVAssetReader(asset: composition)
} catch let e {
    callback(false, e)
    return
}
reader.timeRange = CMTimeRange(start: .zero, duration: composition.duration)
// AVAssetReaderOutput
audioOutput = AVAssetReaderAudioMixOutput(audioTracks: audioTracks, audioSettings: nil)
audioOutput.alwaysCopiesSampleData = false
audioOutput.audioMix = audioMix
if reader.canAdd(audioOutput) {
    reader.add(audioOutput)
}
if !reader.startReading() {
    callback(false, reader.error)
    return
}

// -----編碼----
// AVAssetWriter
do {
    writer = try AVAssetWriter(outputURL: outputUrl, fileType: .mp3)
} catch let e {
    callback(false, e)
    return
}
writer.shouldOptimizeForNetworkUse = true
let audioOutputSettings: [String : Any] = [
    AVFormatIDKey: NSNumber(value: kAudioFormatMPEGLayer3),
    AVNumberOfChannelsKey: NSNumber(value: 2),
    AVSampleRateKey: NSNumber(value: 44100),
    AVEncoderBitRateKey: NSNumber(value: 128000)
]
// AVAssetWriterInput
audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioOutputSettings)
if writer.canAdd(audioInput) {
    writer.add(audioInput)
}
writer.startWriting()
writer.startSession(atSourceTime: .zero)
// 準備寫入數據
videoInput.requestMediaDataWhenReady(on: inputQueue) { [weak self] in
    ...
}

其中audioOutputSettings的4項就對應上面分析過的: 編碼格式,聲道數,採樣率,比特率;這些設置最終決定了編碼後音頻的格式、音頻的存儲空間及音質;
而且這些設置都是固定組合的,不同編碼格式Format所需的Key有所不一樣;

wav/pcm 格式設置(需要pcm相關設置):

let audioOutputSettings: [String : Any] = [
        AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),
        AVNumberOfChannelsKey: NSNumber(value: 2),
        AVSampleRateKey: NSNumber(value: 44100),
        AVLinearPCMBitDepthKey: NSNumber(value: 16),
        AVLinearPCMIsBigEndianKey: NSNumber(value: false),
        AVLinearPCMIsFloatKey: NSNumber(value: false),
        AVLinearPCMIsNonInterleaved: NSNumber(value: false)
    ]
  • FFmpeg
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章