轉自: https://www.freehacker.cn/media/codec-h264/
簡述
H.264,又稱爲 MPEG-4 第10部分,高級視頻編碼(英語:MPEG-4 Part 10, Advanced Video Coding,縮寫爲 MPEG-4 AVC)是一種面向塊的基於運動補償的視頻編碼標準 。
對於視頻序列樣本來說,使用 H.264 編碼器能夠比使用有運動補償的 MPEG-4 編碼器降低50%的比特率(bps)。在沒有運動補償的情況下,H.264 編碼器的效率至少比 MPEG-4 編碼器高3倍,比 M-JPEG 編碼器高6倍。除了能夠顯著的提高編碼效率外,H.264的優點還包括:提供高質量的圖像、容錯能力強、網絡適應性強、低時延等。
有關 H264 詳細的介紹可以參考
維基百科:H.264/MPEG-4 AVC,中文地址/英文地址
H264相關標準,中英對照版本見文獻。
H.264原理
視頻編碼的核心思想是是去除冗餘信息,冗餘信息包括以下幾個方面:
- 空間冗餘:圖像相鄰像素之間有較強的相關性
- 時間冗餘:視頻序列的相鄰圖像之間內容相似
- 編碼冗餘:不同像素值出現的概率不同
- 視覺冗餘:人的視覺系統對某些細節不敏感
- 知識冗餘:規律性的結構可由先驗知識和背景知識得到
- 視頻編解碼器(編碼器/解碼器)是指兩個協同運行的壓縮-解壓算法。使用不同標準的視頻編解碼器通常彼此之間互不兼容。
H.264壓縮方法如下:
- 分組:把幾幀圖像分爲一組(GOP,也就是一個序列),爲防止運動變化,幀數不宜取多;
- 定義幀:將每組內各幀圖像定義爲三種類型,即I幀、B幀和P幀;
- 預測幀:以I幀做爲基礎幀,以I幀預測P幀,再由I幀和P幀預測B幀;
- 數據傳輸:最後將I幀數據與預測的差值信息進行存儲和傳輸。
H.264編解碼流程如下:
H.264編碼流程
H.264幀場
幀與場
要想了解幀與場的概念,需先掌握逐行掃描和隔行掃描的區別。在英語中,逐行掃描爲Progressive Scanning,隔行掃描爲Interlace Scanning。
逐行比較好理解,假設一幀圖像的大小是704x576,那麼逐行的話就是576行。隔行圖像,是早期電視信號中引入的概念,把一幀圖像分爲上下兩場,兩場圖像在時間上具有先後,但傳輸時同時傳送到顯示端,顯示端在顯示按各自的時間分開進行顯示。該方式主要是利用了人眼的餘輝效應,通過隔行顯示,提高了顯示的流暢性。
場(Field)和幀(Frame)的概念一目瞭然:
- 隔行掃描得到場,場分爲底場和頂場,底場包含偶數行數據,頂場包含奇數行數據;
- 逐行掃描得到幀,幀包含一張圖片完整的信息,底場和頂場一起包含完整的一幀信息。
對於一個具體的序列參數集來說,編碼場的寬度和編碼幀的寬度是相同的,而編碼場的高度是是編碼幀的高度的一半。
幀組成
H.264多了個圖像組成一個視頻系列(GOP),每個圖像由一幀(Frame)組成。幀又可以分成一個或幾個片(Slice)。片由宏塊(Macro Block)組成,一幀中每個片的宏塊數不一定相同。每個宏塊由一個16×16的亮度數組和兩個8×8的色差數組組成。一個720×480分辨率的圖像可以被劃分爲1350(45×30)個宏塊。
宏塊是編碼處理的基本單元。一個幀是可以分割成多個片來編碼的,構成I_Slice、P_Slice、B_Slice、SP_Slice和SI_Slice,而一個片編碼之後被打包進一個NAL單元。編碼片相互間獨立,這樣做的目的是爲了限制誤碼的擴散和傳輸。
I_Slice、P_Slice和B_Slice對應於I幀、P幀和B幀,三者之區別如下:
- I_slice :只使用當前片中已解碼的像素進行幀內預測。
- P_slice:可能使用當前片中的像素進行幀內預測,也可能使用前面參考幀進行幀間預測。
- B_slice:可能使用當前片中的象素進行幀內預測,也可能使用前後參考幀進行幀間預測。
幀分類
根據H.264的不同類別,編碼器會使用不同類型的幀,例如I幀、P幀和B幀。
-
I幀(幀內編碼幀)是一種自帶全部信息的獨立幀,無需參考其它圖像便可獨立進行解碼。
視頻序列中的第一個幀始終都是I幀。如果所傳輸的比特流遭到破壞,則需要將I幀用作新查看器的起始點或重新同步點。I幀可以用來實現快進、快退以及其它隨機訪問功能。如果新的客戶端將參與查看視頻流,編碼器將以相同的時間間隔或者根據要求自動插入I幀。I幀的缺點在於它們會佔用更多的數據位,但從另一方面看,I幀不會產生可覺察的模糊現象。
-
P幀(幀間預測編碼幀)需要參考前面的I幀和/或P幀的不同部分才能進行編碼。
與I幀相比,P幀通常佔用更少的數據位,但其缺點是,由於P幀對前面的P和I參考幀有着複雜的依賴性,因此對傳輸錯誤非常敏感。
-
B幀(雙向預測編碼幀)需要同時以前面的幀和後面的幀作爲參考幀。
下圖爲帶有I幀、B幀和P幀的典型視頻序列。P幀只需要參考前面的I幀或P幀,而B幀則需要同時參考前面和後面的I幀或P 幀。
當視頻解碼器逐個幀地對比特流進行解碼以便重構視頻時,必須始終從I幀開始解碼。如果使用了P幀和B幀,則必須與參考幀一起解碼。在H.264基準類中,僅使用I幀和P幀。由於基準類沒有使用B幀,所以可以實現低延時,因此是網絡攝像機和視頻編碼器的理想選擇。
幀內預測
在H.264中,將通過新的高級幀內預測方法對I幀進行編碼。這種方法通過對幀中每個宏塊內較小的像素塊進行連續預測,通過一組不同方向上的相鄰塊來預測當前塊,可以大大減少I幀所佔的數據位並保持較高的質量。這一點可通過在與進行幀內編碼的新4×4像素塊相鄰接的前幾個編碼像素中,尋找匹配的像素來實現。通過重複利用已編碼的像素值,可以極大地減少需要編碼的位數。
幀內預測編碼的是預測塊和實際塊差值,這種方法能夠有效減少平滑背景小的空間冗餘。
幀間預測
H.264 通過差分編碼來減少視頻數據量,大多數視頻壓縮標準都採用這種方法:在差分編碼中,會將一個幀與參考幀(即前面的 I 幀或 P 幀)進行對比,然後只對那些相對於參考幀來說發生了變化的像素進行編碼。通過這種方法,可以降低需要進行編碼和發送的像素值。
對差分編碼(包括H.264在內的大多數視頻壓縮標準都採用這種方法)來說,只有第一個圖像(I幀)是將全幀圖像信息進行編碼。在後面的兩個圖像(P幀)中,其靜態部分(即房子)將參考第一個圖像,而僅對運動部分(即正在跑步的人)使用運動矢量進行編碼,從而減少發送和存儲的信息量。
然而,如果視頻中存在大量物體運動的話,差分編碼將無法顯著減少數據量。這時,可以採用基於塊的運動補償技術。基於塊的運動補償考慮到視頻序列中構成新幀的大量信息都可以在前面的幀中找到,但可能會在不同的位置上。所以,這種技術將一個幀分爲一系列的宏塊。然後,通過在參考幀中查找匹配塊的方式,逐塊地構建或者”預測”一個新幀(例如P幀)。如果發現匹配的塊,編碼器只需要對參考幀中發現匹配塊的位置進行編碼。與對塊的實際內容進行編碼相比,只對運動矢量進行編碼可以減少所佔用的數據位。
爲了提高編碼效率,宏塊被分割成更小的子塊,下圖給出了 H.264、MPEG-4和MPEG-2運動補償技術特性對比:
同時,由於運動是個持續的過程,拍攝運動圖像時可能會出現偏移和遮擋,拍攝角度會不停的來回切換,H.264引入了多參考幀的概念。
整數變換
從幀間預測和幀內預測得到的結果需要從空域轉換成頻域,H.264/MPEG-4 AVC採用4×4 DCT-like整數變換。相對於MPEG-2和MPEG-4基於浮點係數的8×8 DCT變換,整數係數能夠消除浮點係數固有的舍入誤差,進而消除浮點係數引起的drifting artifacts。同時,H.264/MPEG-4 AVC較小的塊大小也減少了阻塞和ringing artifacts。
H.264協議中的變化方式主要有三種:4×4殘差變化(整數DCT變換)、16×16幀內模式下4×4亮度直流係數變化(離散哈達瑪變化)、2×2色度直流係數變化(離散哈達瑪變化)。
量化
從整數變化階段得到的係數需要被量化,用以減少整數係數的整體精度,並趨向於消除高頻係數,保持感知質量。量化的原則是在不降低視覺效果的前提下儘量減少圖像編碼長度,減少視覺恢復中不必要的信息。
一般的標量量化器原理如下:
Zij=round(Yij/Qstep)
其中,Yij表示一個宏塊經過整數DCT轉換後的係數,Zij是輸出的量化係數,Qstep是量化步長。量化步長決定了量化器的編碼壓縮率以及圖像精度。如果量化步長較大,則量化值Zij動態範圍較小,其相應的編碼長度較小,但反量化會損失較多的圖像細節信息;如果量化步長較小,則量化值Zij動態範圍較大,其相應的編碼長度較大,但圖像損失較少。H.264編碼器根據圖像值實際動態範圍自動改變量化步長值,在編碼長度和圖像精度之間折衷,達到整體最佳效果。
在H.264中,使用量化參數QP(Quantization Parameter)來標識量化步長的序號,亮度編碼的量化步長Qstep共有52個值,QP爲0-51;色度編碼的量化步長Qstep共有39個值,QP爲0-39。QP取最小值0 時,表示量化最精細;相反,QP取最大值51/39時,表示量化是最粗糙的。亮度編碼的QP每增加6,量化步長Qstep增加一倍。亮度編碼的量化步長信息如下表:
QP | Qstep | QP | Qstep | QP | Qstep | QP | Qstep | QP | Qstep |
---|---|---|---|---|---|---|---|---|---|
0 | 0.625 | 13 | 2.25 | 22 | 8 | 33 | 28 | 44 | 104 |
1 | 0.6875 | 12 | 2.5 | 23 | 9 | 34 | 32 | 45 | 112 |
2 | 0.8125 | 13 | 2.75 | 24 | 10 | 35 | 36 | 46 | 128 |
3 | 0.875 | 14 | 3.25 | 25 | 11 | 36 | 40 | 47 | 144 |
4 | 1 | 15 | 3.5 | 26 | 13 | 37 | 44 | 48 | 160 |
5 | 1.125 | 16 | 4 | 27 | 14 | 38 | 52 | 49 | 176 |
6 | 1.25 | 17 | 4.5 | 28 | 16 | 39 | 56 | 50 | 208 |
7 | 1.375 | 18 | 5 | 29 | 18 | 40 | 64 | 51 | 224 |
8 | 1.625 | 19 | 5.5 | 30 | 20 | 41 | 72 | ||
9 | 1.75 | 20 | 6.5 | 31 | 22 | 42 | 80 | ||
10 | 2 | 21 | 7 | 32 | 26 | 43 | 88 |
循環濾波
H.264 / MPEG-4 AVC定義了一種去塊濾波器(de-blocking filter ),其對16×16宏塊和4×4塊邊界進行操作。 在宏塊的情況下,濾波器旨在去除可能由具有不同估計類型(例如,運動與幀內估計)的相鄰宏塊和/或不同的量化尺度產生的僞像。 在塊的情況下,濾波器旨在去除可能由變換/量化引起的僞像和相鄰塊之間的運動矢量差異。 循環濾波器通常使用內容自適應非線性濾波器來修改宏塊/塊邊界的任一側上的兩個像素。
熵編碼
在進行熵編碼之前,必須對4x4量化係數進行序列化。 根據這些係數是否是原始的運動估計或幀內估計,選擇不同的掃描模式來創建串行化流。 掃描模式將係數從低頻到高頻排列。 然後,由於較高頻率的量化係數趨向於零,所以使用遊程長度編碼來分組尾隨零,導致更有效的熵編碼。
熵編碼將表示運動矢量、量化係數和宏塊頭的符號映射到實際位中,熵編碼通過將較少數量的比特分配給頻繁使用的符號和較大數量的比特到較不頻繁使用的符號來提高編碼效率。
下列表格描述了兩種主要類型的熵編碼:Variable Length Coding (VLC)和Context Adaptive Binary Arithmetic Coding (CABAC)。
Level 和 Profile
H.264 標準的一個重要方面是通過級別(Level)和檔次(Profile)中提供的功能,以最佳的方式支持常見應用和通用格式。Profile 是對視頻壓縮特性的描述(CABAC 呀、顏色採樣數等等),Level 是對視頻本身特性的描述(碼率、分辨率、幀率)。簡單來說,Profile 越高,就說明採用了越高級的壓縮特性。Level 越高,視頻的碼率、分辨率、幀率越高。
H.264 從低到高劃分了很多 Profile 和 Level,在維基百科英文版中能夠看到詳細的表格,在本節末尾會貼出相關表格內容。
H.264 支持四個 Profile,分別爲:
- BP(Baseline Profile):提供I/P幀,僅支持Progressive和CAVLC,多應用於”視頻會話”,如可視電話、會議電視、遠程教學、視頻監控等實時通信領域;
- XP(Extended profile)提供I/P/B/SP/SI幀,僅支持Progressive和CAVLC,多應用於流媒體領域,如視頻點播、基於網絡的視頻監控等;
- MP(Main profile)提供I/P/B幀,支持Progressive和Interlaced,提供CAVLC和CABAC。多應用於數字電視廣播、數字視頻存儲等領域;
- HiP(High profile)在Main profile基礎上新增8*8幀內預測,像素精度提高到10位或14位。多應用於對高分辨率和高清晰度有特別要求的領域。
至於Level和Profile的相關表格如下:
-
H.264 Profile
-
H.264 Level
H.264架構
分層架構
制定H.264的主要目標有兩個:
- 得到高的視頻壓縮比;
- 具有良好的網絡親和性。
爲此,H.264的功能分爲兩層:視頻編碼層(VLC,Video Coding Layer)和網絡抽象層(NAL,Network Abstraction Layer)。
數據格式
視頻編碼層進行視頻數據壓縮、解壓縮操作,而網絡抽象層專門爲視頻編碼信息提供頭文件信息,安排格式以方便網絡傳輸和介質存儲。VCL數據即編碼處理的輸出,它表示被壓縮編碼後的視頻數據序列。在VCL數據傳輸或存儲之前,這些編碼的VCL數據,先被映射或封裝進NAL單元中。每個NAL單元包含一個原始字節序列負載(RBSP,Raw Byte Sequence Payload)、一組對應於視頻編碼數據的NAL頭信息。其具體結構如下圖:
在H.264編碼過程中,存在三種不同的數據形式:
- SODB, String of Data Bits,數據比特串,是最原始的編碼數據,即VCL數據;VCL層是對核心算法引擎,塊,宏塊及片的語法級別的定義,他最終輸出編碼完的數據SODB
- RBSP,Raw Byte Sequence Payload,原始字節序列載荷,在SODB的後面填加了結尾比特(RBSP trailing bits 一個bit”1”)若干比特”0”,以便字節對齊;
- EBSP,Encapsulation Byte Sequence Packets,擴展字節序列載荷,在RBSP基礎上填加了仿校驗字節(0X03)。
加上仿校驗字節的原因是:EBSP被封裝爲NALU時,需要爲其添加開始前綴,如果該NALU對應的Slice爲一幀的開始,則用’0x000000001’,否則使用’0x000001’。
爲了使NALU主體中不包括與開始碼相沖突的,在編碼時,每遇到兩個字節連續爲0,就插入一個字節的0x03。解碼時將0x03去掉。也稱爲脫殼操作。
碼流結構
在H.264中圖像以序列爲單位進行組織,一個序列是一段圖像編碼後的數據流,以IDR幀開始,到下一個IDR幀結束,中間包含若干訪問單元(Access Unit)。從宏觀上來說,SPS、PPS、IDR 幀(包含一個或多個I-Slice)、P 幀(包含一個或多個P-Slice )、B 幀(包含一個或多個B-Slice )共同構成典型的H.264碼流結構。
SPS/PPS
SPS,Sequence Parameter Sets,序列參數集,是H.264碼流序列的第一個NALU,PPS,Picture Parameter Set,圖像參數集,是H.264碼流序列的第二個NALU。
SPS和PPS中包含了初始化H.264解碼器所需要的信息參數,包括編碼所用的profile、level、圖像的寬和高、deblock濾波器等。SPS語法單元存放一個視頻序列共同特徵,而PPS語法單元各個圖像的典型特徵。SPS和PPS都各自對應於一個NALU。
只有視頻序列之間才能切換SPS,即只有IDR幀的第一個slice纔可以切換SPS;只有圖像之間才能切換PPS,即只有每幀圖像的第一個slice才能切換PPS。
IDR/P/B
IDR,Instantaneous Decoder Refresh,即時解碼器刷新,是H.264碼流序列的第三個NALU。
IDR幀都是I幀,但是I幀並不一定是IDR幀。H.264 引入 IDR 圖像是爲了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數集,開始一個新的序列。這樣,如果前一個序列出現重大錯誤,在這裏可以獲得重新同步的機會。IDR圖像之後的圖像永遠不會使用IDR之前的圖像的數據來解碼。
在IDR幀之後可能存在I幀、P幀和B幀,這個具體看使用的是哪種Profile。
H.264語法結構
NALU,Network Abstract Layer Unit,是H.264的最高抽象層,H.264的所有語法結構最終都被封裝成NALU,同時會加入一些網絡相關信息。碼流中的NALU單元必須定義合適的分隔符,否則無法區分。H.264 視頻壓縮標準的附錄B採用前綴碼“00 00 01”/“00 00 00 01”作爲NALU的分隔符,可以通過搜索前綴碼“00 00 01”/“00 00 00 01”來識別一個NALU。
H.264視頻流是以NAL單元傳送的,但在一個NAL單元裏面,可能既存放I-Slice(P-Slice或B-Slice),也可能存放圖像的其他信息,比如SPS、PPS。根據H.264語法結構,根據的NAL類型可以分爲:
NAL_SLICE = 1 SLICE非IDR不分割
NAL_SLICE_DPA = 2 SLICE數據分割塊A
NAL_SLICE_DPB = 3 SLICE數據分割快B
NAL_SLICE_DPC = 4 SLICE數據分割塊C
NAL_SLICE_IDR = 5 SLICE關鍵幀
NAL_SEI = 6 補充增強信息單元幀
NAL_SPS = 7 序列參數集
NAL_PPS = 8 圖像參數集
NAL_AUD = 9 分界符
NAL_EOSEQ = 10 序列結束
NAL_EOSTREAM = 11 碼流結束
NAL_FILLER = 12 填充
= 13
= ...
= 23 13~23保留
= 24
= ...
= 31 24~32不保留,RTP打包時會用到
將數據塊分割爲A、B、C,主要目的是爲了對重要程度不同的數據進行不同程度的保護。其中24~32類型是不保留的,其在RTP打包時會用到:
類型取值 | 對應類型 | 功能 |
---|---|---|
24 | STAP-A | Single-time aggregation packet |
25 | STAP-B | Single-time aggregation packet |
26 | MTAP16 | Multi-time aggregation packet |
27 | MTAP24 | Multi-time aggregation packet |
28 | FU-A | Fragmentation unit |
29 | FU-B | Fragmentation unit |
30-31 | undefined |
FU_A
對於比較大的NALU單元,是無法一次通過RTP發送的(RTP的MTU爲1500),所以必須要拆包,將較大的NALU拆分爲FU-A包。這裏面有拆包和解包兩個概念:
- 拆包:當編碼器在編碼時需要將原有一個NAL按照FU-A進行分片,原有的NAL的單元頭與分片後的FU-A的單元頭有如下關係:
原始的NAL頭的前三位爲FU indicator的前三位,原始的NAL頭的後五位爲FU header的後五位,
FU indicator與FU header的剩餘位數根據實際情況決定。
- 解包:當接收端收到FU-A的分片數據,需要將所有的分片包組合還原成原始的NAl包時,FU-A的單元頭與還原後的NAL的關係如下:
還原後的NAL頭的八位是由FU indicator的前三位加FU header的後五位組成,
即:nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)
開源實現
H.264 的開源實現包括:OpenH264 和 x264。OpenH264 是思科實現的開源 H.264 編碼,OpenH264 是思科實現的開源 H.264 編碼。兩者的對比如下:
- OpenH264 CPU 的佔用相對 x264 低很多;支持SVC 編碼
- OpenH264 只支持 baseline profile,x264 支持更多 profile;
- x264 需要專利費用,而 OpenH264 不需要專利費用; 不支持SVC
- x264 的主要功能在於進行 H.264 的視頻編碼,而不是作爲解碼器之用。
其他標準
目前能與H.264相提並論的編碼算法包括:
HEVC/H.265:開源實現包括 libde265 和 x265,需專利費;
VP8:開源實現爲 libvpx,無專利費;
VP9:開源實現爲 ibvpx,無專利費。
幾種編碼方案中,HEVC 對 VP9 和 H.264 在碼率上有較大優勢,在相同 PSNR 下分別節省了 48.3% 和 75.8%。H.264 在編碼時間上有巨大優勢,對比 VP9 和 HEVC(H.265) ,HEVC 是 VP9 的 6 倍,VP9 是 H.264 的將近 40 倍。
在H.264之前,還有一些前輩算法,包括:
- H.261、H.263
- MPEG-1、MPEG-2、MPEG-4
- JPEG、JPEG2000
- AVS
參考文檔
- H.264/MPEG-4 AVC Video Compression Tutorial
- Video Compression Video Coding for Next Generation Multimedia
- H.264/AVC 技術與應用簡介
- The H.264/MPEG4 Advanced Video Coding Standard and its Applications
- H.264/MPEG-4 Advanced Video Coding
- Understanding the Application: An Overview of the H.264 Standard
- H.264 Advanced Video Compression Standard
- Video coding with H.264/AVC: Tools, Performance, and Complexity
- A STUDY OF MPEG-2 AND H.264 VIDEO CODING
- H.264 and MPEG-4 Video Compression Video Coding for Next-generation Multimedia
- The H.264 Advanced Video Compression Standard, Second Edition