視頻編碼之I,P,B幀
編碼主要是想辦法壓縮視頻的大小。
使用幀間編碼技術可以去除時間上的冗余信息,具體包括以下幾個部分。
- 運動補償:運動補償是通過先前的局部圖像來預測、補償當前的局部圖像,它是減少幀序列冗余信息的有效方法。
- 運動表示:不同區域的圖像需要使用不同的運動矢量來描述運動信息。
- 運動估計:運動估計是從視頻序列中抽取運動信息的一整套技術。
使用幀內編碼技術可以去除空間上的冗余信息。
對于視頻,ISO同樣也制定了標準:Motion JPEG即MPEG,MPEG算法是適用于動態視頻的壓縮算法,它除了對單幅圖像進行編碼外,還利用圖像序列中的相關原則去除冗余,這樣可以大大提高視頻的壓縮比。截至目前,MPEG的版本一直 在不斷更新中,主要包括這樣幾個版本:Mpeg1(用于VCD)、Mpeg2(用于 DVD)、Mpeg4 AVC(現在流媒體使用最多的就是它了)。
相比較于ISO制定的MPEG的視頻壓縮標準,ITU-T制定的H.261、 H.262、H.263、H.264一系列視頻編碼標準是一套單獨的體系。其中, H.264集中了以往標準的所有優點,并吸取了以往標準的經驗,采用的是簡潔設計,這使得它比Mpeg4更容易推廣。現在使用最多的就是H.264標準,H.264創造了多參考幀、多塊類型、整數變換、幀內預測等新的壓縮技術,使用了更精細的分像素運動矢量(1/4、1/8)和新一代的環路濾波器, 這使得壓縮性能得到大大提高,系統也變得更加完善
編碼的概念
在H264中,三種類型的幀數據分別為
IPB幀
視頻壓縮中,每幀都代表著一幅靜止的圖像。而在進行實際壓縮時,會采取各種算法以減少數據的容量,其中IPB幀就是最常見的一種。
- I幀:幀內編碼幀(intra picture),I幀通常是每個GOP(MPEG所使用 的一種視頻壓縮技術)的第一個幀,經過適度地壓縮,作為隨機訪問的參考點,可以當成靜態圖像。I幀可以看作一個圖像經過壓縮后的產物,I幀壓縮可以得到6:1的壓縮比而不會產生任何可覺察的模糊現象。I幀壓縮可去掉視頻的空間冗余信息,下面即將介紹的P幀和B幀是為了去掉時間冗余信息。
- P幀:前向預測編碼幀(predictive-frame),通過將圖像序列中前面已編碼幀的時間冗余信息充分去除來壓縮傳輸數據量的編碼圖像,也稱為預測幀。P幀表示的是這一幀跟之前的一個I幀(或P幀)的差別**,解碼時需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面**。(也就是差別幀,P幀沒有完整畫面數據,只有與前一幀的畫面差別的數據)
- B幀:雙向預測內插編碼幀(bi-directional interpolated prediction frame),以前面的I或P幀和后面的P幀為參考幀,“找出”B幀“某點”的預測值和兩個運動矢量,并取預測差值和運動矢量傳送。接收端根據運動矢量在兩個參考幀中“找出(算出)”預測值并與差值求和,得到B幀“某點”樣值,從而可得到完整的B幀。換言之,要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過前后畫面的與本幀數據的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU的負荷會比較大。
基于上面的定義,我們可以從解碼的角度來理解IPB幀。 I幀自身可以通過視頻解壓算法解壓成一張單獨的完整視頻畫面, 所以I幀去掉的是視頻幀在空間維度上的冗余信息。 P幀需要參考其前面的一個I幀或者P幀來解碼成一張完整的視頻畫面。 B幀則需要參考其前一個I幀或者P幀及其后面的一個P幀來生成一 張完整的視頻畫面,所以P幀與B幀去掉的是視頻幀在時間維度上的冗余信息。
以一個經典的例子去講解這個知識點可能會比較直觀一點。如圖
【免費分享】資料包括《Andoird音視頻開發必備手冊+音視頻學習視頻+學習文檔資料包+大廠面試真題+2022最新學習路線圖》等
有需要的點擊下方鏈接領取
FFmpegWebRTCRTMPRTSPHLSRTP播放器-音視頻流媒體高級開發
I幀記錄的就是完整的信息,這里不用多說。看一下I幀與P幀的關系。首先我們看原始的圖片,P幀比I幀多了一個小方塊。所以P幀最后的存儲的就只是一個小方塊的信息。可以理解為I幀與P幀組合起來就得到原始的圖片了。
同理,來看一下B幀。可以看到B幀與I幀,p幀的組合才會形成原始圖片。
GOP(序列)和IDR
在H264中圖像以序列為單位進行組織,一個序列是一段圖像編碼后的數據流。 一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。
H.264 引入 IDR 圖像是為了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數集,開始一個新的序列。這樣,如果前一個序列出現重大錯誤,在這里可以獲得重新同步的機會。
IDR圖像之后的圖像永遠不會使用IDR之前的圖像的數據來解碼。 一個序列就是一段內容差異不太大的圖像編碼后生成的一串數據流。當運動變化比較少時,一個序列可以很長,因為運動變化少就代表圖像畫面的內容變動很小,所以就可以編一個I幀,然后一直P幀、B幀了。當運動變化多時,可能一個序列就比較短了,比如就包含一個I幀和3、4個P幀。 在視頻編碼序列中,GOP即Group of picture(圖像組),指兩個I幀之間的距離,Reference(參考周期)指兩個P幀之間的距離。兩個I幀之間形成一組圖片,就是GOP(Group Of Picture)。
【GOP示意圖】
PTS和DTS
【為什么會有PTS和DTS的概念】
通過上面的描述可以看出:P幀需要參考前面的I幀或P幀才可以生成一張完整的圖片,而B幀則需要參考前面I幀或P幀及其后面的一個P幀才可以生成一張完整的圖片。這樣就帶來了一個問題:在視頻流中,先到來的 B 幀無法立即解碼,需要等待它依賴的后面的 I、P 幀先解碼完成,這樣一來播放時間與解碼時間不一致了,順序打亂了,那這些幀該如何播放呢?這時就引入了另外兩個概念:DTS 和 PTS。
【PTS和DTS】
先來了解一下PTS和DTS的基本概念:
DTS(Decoding Time Stamp):即解碼時間戳,這個時間戳的意義在于告訴播放器該在什么時候解碼這一幀的數據。 PTS(Presentation Time Stamp):即顯示時間戳,這個時間戳用來告訴播放器該在什么時候顯示這一幀的數據。
雖然 DTS、PTS 是用于指導播放端的行為,但它們是在編碼的時候由編碼器生成的。
在視頻采集的時候是錄制一幀就編碼一幀發送一幀的,在編碼的時候會生成 PTS,這里需要特別注意的是 frame(幀)的編碼方式,在通常的場景中,編解碼器編碼一個 I 幀,然后向后跳過幾個幀,用編碼 I 幀作為基準幀對一個未來 P 幀進行編碼,然后跳回到 I 幀之后的下一個幀。編碼的 I 幀和 P 幀之間的幀被編碼為B 幀。
之后,編碼器會再次跳過幾個幀,使用第一個 P 幀作為基準幀編碼另外一個 P 幀,然后再次跳回,用 B 幀填充顯示序列中的空隙。這個過程不斷繼續,每 12 到 15 個 P 幀和 B 幀內插入一個新的 I 幀。P 幀由前一個 I 幀或 P 幀圖像來預測,而 B 幀由前后的兩個 P 幀或一個I幀和一個P幀來預測,因而編解碼和幀的顯示順序有所不同,如下所示:
過程大概如上圖所以。我們接下來一步一步講解上面的過程。
首先是我們的幀序號,一開始,幀序號是按照順序來的,這一點沒有疑問。然后這些順序幀也都是有類型的。如上所述第一幀是I幀,第二幀是B幀,依次類推得到我們的幀類型了。我們要正常播放肯定就是需要按照我們原始的需要播放,也就是按照1...7這種需要播放。所以我們的PTS也是1...7這樣順序顯示的。
現在到編碼順序了,這里也是關鍵點了,**編解碼器編碼一個I幀,然后向后跳過幾個幀,用編碼I幀作為基準幀對一個未來P幀進行編碼。然后跳回到I幀之后的下一個幀。編碼的I幀和P幀之間的幀被編碼為B幀。**如下圖。
我們根據第一到七步的順序,得到編碼順序對應的幀序號為
而這些序號對應的幀類型為。
那解碼的時間戳為順序的,即1234567
到這里發現問題了沒有?如果我們按照解碼的時間戳來顯示的話,那么顯示的順序就是IPBBPBB和我們原來的IBBPBBP順序是不一樣的。這樣相當于修改了我們的視頻了。所以需要按照PTS去調整。怎么調整呢?
首先看接受到的視頻流(幀類型)這一行。這一行對應的原始的,根據這一行的幀類型,去需要幀類型對應的幀序號,也就得到了對應的PTS這一行的數據。
那么最后,對應的PTS這個數據去調整DTS,也就得到了調整后的DTS。這整一個過程有點繞,大家看不懂的話,慢慢的多看幾遍就能理解了。