前言
總結的一些音視頻相關的知識,文末總結有傳送門。
概念
- 協議層(Protocol Layer):該層處理的數據為符合特定流媒體協議規范的數據,例如http,rtmp,file等;
- 封裝層(Format Layer):該層處理的數據為符合特定封裝格式規范的數據,例如mkv,mp4,flv,mpegts,avi等;
- 編碼層(Codec Layer):該層處理的數據為符合特定編碼標準規范的數據,例如h264,h265,mpeg2,mpeg4等;
- 像素層(Pixel Layer):該層處理的數據為符合特定像素格式規范的數據,例如yuv420p,yuv422p,yuv444p,rgb24等;
此分類和圖片來自雷神的博客,這里是鏈接。
很多多媒體數據流需要同時包含音頻數據和視頻數據,這時通常會加入一些用于音頻和視頻數據同步的元數據,例如字幕。這三種數據流可能會被不同的程序,進程或者硬件處理,但是當它們傳輸或者存儲的時候,這三種數據通常是被封裝在一起的。通常這種封裝是通過視頻文件格 式來實現的,例如常見的.mpg, .avi, .mov, .mp4, .rm, .ogg or .tta。 這些格式中有些只能使用某些編解碼器,而更多可以以容器的方式使用各種編解碼器。
視頻壓縮原理
1、壓縮的方向
數字化后的視頻信號具有很大的數據冗余,壓縮的本質就是去掉這些冗余。
- 空間冗余,視頻的背景和整體顏色相近并且平穩變化,可以利用幀內編碼進行壓縮;(無損)
- 時間冗余,兩個視頻幀之間具有強相關性,利用運動估計和運動補償進行幀間壓縮;(無損)
- 結構冗余,圖像內部存在相似性,通過這種關系可以進行分形編碼;
- 編碼冗余,出現概率大的顏色編碼長度短,概率小的顏色編碼長度長;(可變長度編碼)
- 視覺冗余,利用人眼對亮度和色度的敏感度不同,在編碼時進行數據壓縮;(有損壓縮)
2、變換
空間域描述的圖像相關性不太明顯,需要變換到頻率域。常用的正交變換有離散傅里葉變換,離散余弦變換等等。數字視頻壓縮過程中應用廣泛的是離散余弦變換。
- 空間域(spatial domain),又稱圖像空間(image space)。由圖像像元組成的空間。在圖像空間中以長度(距離)為自變量直接對像元值進行處理稱為空間域處理。
- 頻率域(spatial frequency domain),以空間頻率為自變量描述圖像的特征,可以將一幅圖像像元值在空間上的變化分解為具有不同振幅、空間頻率和相位的簡振函數的線性疊加,圖像中各種空間頻率成分的組成和分布稱為空間頻譜。這種對圖像的空間頻率特征進行分解、處理和分析稱為頻率域處理或波數域處理。
圖像處理中的空間域就是像素域,在空間域的處理就是在像素級的處理,如在像素級的圖像疊加。通過傅立葉變換后,得到的是圖像的頻譜。表示圖像的能量梯度。
借用雷神blog的三張圖來闡述效果:
H.264格式
H.264是音視頻知識中,必須深入了解的部分。
先介紹一些基本的概念
I幀是關鍵幀,解碼時只需要本幀數據;
P幀是參考幀,表示這一幀與前一個關鍵幀(或P幀)的差別;
B幀是雙向參考幀,表示本幀與前后幀的差別;(B幀壓縮率高,解碼復雜,直播中較少用)
IDR幀是第一個I幀,為的是和其他I幀區別開,方便控制編碼和解碼;
IDR會導致DPB(DecodedPictureBuffer 參考幀列表)清空,而I不會。
GOP(Group Of Picture)是圖像組,是一組連續的畫面;(直播實現秒開,關鍵就是CDN節點緩存GOP,編碼器拿到第一個GOP后馬上解碼播放)
幀內壓縮:當壓縮一幀圖像時,僅考慮本幀的數據而不考慮相鄰幀之間的冗余信息;(幀內壓縮一般達不到很高的壓縮,跟編碼jpeg差不多)
幀間壓縮:利用相鄰幀的相關性提高壓縮量,減少冗余;(運動補償和運動估計是常用的技術)
編碼順序
簡單描述下編碼的過程,假設我們處理的第一幀是IDR幀:
1.編碼IDR幀
2.根據scenecut 和 min-keyint的設置,向后移動 min-keyint的距離,開始判定是否為scenechange,直到判定滿足,或者到達keyint設置值的距離時候停止。同時記錄判定條件不完全滿足時候的位置。
3.編碼找到的為指針,亦為IDR幀,GOP形成。
4.根據2步中得到的判定條件不完全滿足的位置,將對應幀按時間順序用I編碼。
5.找到最頭上IDR和離其最近的I幀形成的Sub-GOP(嚴格意義上說此處并非GOP因為GOP之間不能交換信息,)結合bframes的設定大小,推斷P幀出現的位置。具體而言,按時間順序走每一幀比較該幀用P編碼和B編碼時的視覺誤差和復雜度何者更大,根據某些公式推導出此處應該用何種幀類型,再向后移一幀;如果直到bframes規定的值都未出現P,則強制插入一幀P。這樣就決定了每個sub-GOP內P幀的位置。
6.最后一步,根據I/IDR/P形成的子區間,按時間順序編碼各幀為B幀。
舉例:100-120幀這樣的一段視頻
第一步結束后編碼完成 100幀
第二步結束后可能編碼完成 120幀和110幀 (IDR幀)同時找出了104,108, 115幀應該編碼為I
第四步結束后編碼完成104 108 115 幀為I
第五步對 100-104 104- 108 108-110 110 – 115 115-120五個子區間,判斷P幀出現的位置并編碼有可能判斷出102 113 118 為p幀
最后一步在編碼之間的部分為B幀
于是解碼過程的輸出幀順序其實是
100 110 104 108 102 101 103 105 106 109….
此例來自360文庫,但是原文鏈接已經不能用,歡迎告知出處以備注。
iOS的H.264編解碼
使用VideoToolbox硬編碼H.264
使用VideoToolbox硬解碼H.264
音頻壓縮原理
數字音頻壓縮編碼在保證信號在聽覺方面不產生失真的前提下,對音頻數據信號進行盡可能大的壓縮。數字音頻壓縮編碼采取去除聲音信號中冗余成分的方法來實現。所謂冗余成分指的是音頻中不能被人耳感知到的信號,它們對確定聲音的音色,音調等信息沒有任何的幫助。
冗余信號包含人耳聽覺范圍外的音頻信號以及被掩蔽掉的音頻信號等。
人耳聽覺的掩蔽效應:當一個強音信號與一個弱音信號同時存在時,弱音信號將被強音信號所掩蔽而聽不見,這樣弱音信號就可以視為冗余信號而不用傳送。
頻譜掩蔽效應
一個頻率的聲音能量小于某個閾值之后,人耳就會聽不到,這個閾值稱為最小可聞閾。當有另外能量較大的聲音出現的時候,該聲音頻率附近的閾值會提高很多,即所謂的掩蔽效應。
時域掩蔽效應
當強音信號和弱音信號同時出現時,還存在時域掩蔽效應。即兩者發生時間很接近的時候,也會發生掩蔽效應。時域掩蔽過程曲線如圖所示,分為前掩蔽、同時掩蔽和后掩蔽三部分。
- PCM是編碼格式,經過話筒錄音后直接得到的未經壓縮的數據流;
數據大小=采樣頻率*采樣位數*聲道*秒數/8。
采樣定理表明采樣頻率必須大于被采樣信號帶寬的兩倍,另外一種等同的說法是奈奎斯特頻率必須大于被采樣信號的帶寬。如果信號的帶寬是 100Hz,那么為了避免混疊現象采樣頻率必須大于200Hz。換句話說就是采樣頻率必須至少是信號中最大頻率分量頻率的兩倍,否則就不能從信號采樣中恢復原始信號。
- AAC是編解碼標準,基于MPEG-2的音頻編碼技術;
使用AudioToolbox編碼AAC
使用AudioToolbox播放AAC
PCM采樣率是44100Hz,那么AAC碼率可設置64000bps;
如果是16K,可設置為32000bps;
MP3是封裝格式,所存放數據使用的編碼方式稱為MPEG1 Layer-3 ;
AMR是封裝格式,專用于有效地壓縮語音頻率;
WAV是封裝格式,里面可以存放多種編碼格式的數據,一般是PCM數據;
零碎的知識
FLV封裝格式是由一個FLV Header文件頭和一個一個的Tag組成的。Tag中包含了音頻數據以及視頻數據。FLV的結構如下圖所示。
FLV(Flash Video)是Adobe公司設計開發的一種流行的流媒體格式,由于其視頻文件體積輕巧、封裝簡單等特點,使其很適合在互聯網上進行應用。
RTSP:實時流傳輸協議,是TCP/IP協議體系中的一個應用層協議;
M4A:.m4a是MPEG-4 音頻標準的文件的擴展名,Apple在iTunes以及 iPod中使用“.m4a”以區別MPEG4的視頻和音頻文件;
音視頻同步:時間戳,時間戳即為一幀的采集時間,音視頻采取同一個參考時間,給每個幀打上時間戳。
rtmp發送音視頻:xcode中編譯librtmp庫,遵循rtmp協議,將數據發送到指定服務器;
AudioToolbox.framework:提供CoreAudio的中高級別的API服務,處理電話和其他高優先級語音處理而導致的中斷和恢復操作等;
AudioUnit.framework:提供DSP數字信號處理相關的插件,包括編解碼,混音,音頻均衡等;
AVFoundation.framework:提供一個精簡的音樂播放類,可以播放所有IOS支持的音頻;
OpenAL.framework:提供3D音效播放;
AVFoundation相關
AVAssetExportSession
AVAssetExportSession類可以把AVAsset對應的源文件,轉換成預先設置的格式。
exportPresetsCompatibleWithAsset 可以導出可配置格式的列表;
Error相關
AVAssetWriter
AVAssetWriter經常報出錯誤
AVAssetWriter startSessionAtSourceTime: Cannot call method when status is 0
查看文檔,知道status=0表示未知,可知應該是沒有初始化成功AVAssetWriter;
typedef NS_ENUM(NSInteger, AVAssetWriterStatus) {
AVAssetWriterStatusUnknown = 0,
AVAssetWriterStatusWriting,
AVAssetWriterStatusCompleted,
AVAssetWriterStatusFailed,
AVAssetWriterStatusCancelled
};
EXC_BAD_ACCESS
mTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
檢查sampleBuffer是否為空或者引用是否有retain;
expectsMediaDataInRealTime = YES導致視頻斷斷續續
目前的解釋是:
expectsMediaDataInRealTime=YES
時需要interval=20ms左右的音頻幀
sdk提供的音頻回調是50ms,expectsMediaDataInRealTime=YES的時候會導致音頻斷斷續續(幀數不夠);
驗證:同樣的寫法
expectsMediaDataInRealTime=YES
,當音頻幀的interval=20ms左右時,音頻不卡。
總結
此篇小結并沒有講完自己在研發直播APP過程中,了解的音視頻知識。因為在之前的文集中,已經零碎介紹了一部分知識,不想再贅述。
本人也不是專門做音視頻開發的,只是在研發過程中,遇到這些知識,不懂的就查,作為知識儲備。故而總結的內容,也有不少的部分是來自于其他blog,比如說雷神。
想深入學習音視頻開發,還是多到雷神的blog學習,這里是傳送門。