H.264 編碼基礎知識

說明,以下內容很多參考 從零瞭解H.264結構

基本資料

H.264,又稱爲MPEG-4第10部分,高級視頻編碼(英語:MPEG-4 Part 10, Advanced Video Coding,縮寫爲MPEG-4 AVC)是一種面向塊,基於運動補償的視頻編碼標準。由ITU-T視頻編碼專家組與ISO/IEC聯合工作組開發。

H.264 協議標準

音視頻基礎知識

在線視頻興起之前,互聯網上看片的主要方式是下載到電腦後觀看。比如下載了一個 test.mp4的視頻,這個 mp4是一個容器,又叫封裝格式,就是把已經編碼封裝好的視頻、音頻按照一定的規範放到一起。常見的容器格式有: avi, mp4, mov, ts, mkv, rmvb/rm, wmv, flv, 3gp, asf, webm 。
裸視頻是非常大的,所以需要對視頻做編碼壓縮,常見的視頻編碼格式有: mpeg-1, mpeg-2, mpeg-4, H.264/AVC/mpeg-4part 10, h.265/hevc, vc-1, RealVideo, AVS 。

在這裏插入圖片描述

H.264 視頻編碼

視頻編碼主要是利用空間、時間的冗餘信息進行編碼達到壓縮的目的。空間冗餘信息壓縮是做每一幀圖片內的壓縮,跟 jpeg 圖片壓縮類似,可能會是降採樣、聯合周邊像素信息等方式來進行編碼。 時間冗餘信息主要是參考前後幀的信息來進行編碼,比如前後兩幀的圖片通常是有很多像素點是一樣的,比如要表示兩針圖片的信息,能想到最簡單的方式就是用第一幀的全量信息+第二幀相對第一幀有變化的變量信息來表示。H.264 的編碼很複雜,但是大體的原理就是利用空間、時間信息來編碼。
因爲有利用時間信息來編碼,所以必然要利用多幀的圖片來編碼,所以需要緩存多幀信息,給編解碼以及視頻流帶來一些需要權衡的問題,比如要利用更多前後幀信息來進行編碼,能夠提高壓縮比,但是相應的延遲就會比較高,對於實時視頻推流是需要權衡的;另外解碼順序和渲染順序也需要注意。

簡介

H.264 編碼功能分爲兩層,VCL(視頻編碼層/Video Coding Layer)和 NAL(網絡提取層/Network Abstraction Layer)。VCL 主要分爲 5 部分: 幀間和幀內預測(Estimation)、變換(Transform)和反變換、量化(Quantization)和反量化、環路濾波(Loop Filter)、熵編碼(Entropy Coding)。VCL 負責怎麼高效的進行編碼,編碼後的數據怎麼進行存儲和傳輸由 NAL 來負責,存到了NAL單元(NALU)。一幀圖片經過 H.264 編碼器之後,就被編碼爲一個或多個片(slice),而裝載着這些片(slice)的載體,就是 NALU 了。片(slice)是 H.264 中提出的新概念,是通過編碼圖片後切分通過高效的方式整合出來的概念,一張圖片至少有一個或多個片(slice)。除了裝載編碼數據的slice,有些NALU裝載了編碼的一些 meta 信息,比如 SPS(Sequence parameter set), PPS(Picture parameter set)。

在這裏插入圖片描述

在這裏插入圖片描述

  • 1 Frame (幀) = 1…n個Slice (片)1 Slice (片) = 1…n個Marcoblock(宏塊)1 Marcoblock(宏塊) = 16x16yuv數據
  • 1 Slice (片) = Slice Header + Slice Data
  • 1 NALU = 一組對應於視頻編碼的NALU頭部信息 + 一個原始字節序列負荷(RBSP,Raw Byte Sequence Payload).

NALU

H.264的結構全部都是以 NALU 爲主,理解了 NALU,就理解了 H.264 的結構。一個 NALU 由 NAL頭+RBSP組成。一個原始的 H.264 NALU 單元常由 [StartCode] [NALU Header] [NALU Payload]三部分組成,其中 Start Code 用於標示這是一個 NALU 單元的開始,必須是 00 00 00 0100 00 01

在這裏插入圖片描述

NALU Header

NAL Header 由三部分組成,F/forbidden_bit(1bit),NRI/nal_reference_bit(2bits)(優先級),Type/nal_unit_type(5bits)(類型)。

+---------------+ 
|0|1|2|3|4|5|6|7| 
+-+-+-+-+-+-+-+-+ 
|F|NRI| Type    |
+---------------+ 

在這裏插入圖片描述

比較經常會用到的 NALU 類型有:

00 00 00 01 06:  SEI信息   
00 00 00 01 67:  0x67&0x1f = 0x07 :SPS
00 00 00 01 68:  0x68&0x1f = 0x08 :PPS
00 00 00 01 65:  0x65&0x1f = 0x05: IDR Slice
00 00 00 01 41:  0x41&0x1f = 0x01: Coded slice of a non-IDR picture

參數集是 H.264 標準的一個新概念,是一種通過改進視頻碼流結構增強錯誤恢復能力的方法。
SPS序列參數集 (包括一個圖像序列的所有信息,即兩個 IDR 圖像間的所有圖像信息,如圖像尺寸、視頻格式等)。
PPS圖像參數集 (包括一個圖像的所有分片的所有相關信息, 包括圖像類型、序列號等,解碼時某些序列號的丟失可用來檢驗信息包的丟失與否)

分片(Slice)

我們可以理解爲一 張/幀 圖片可以包含一個或多個分片(Slice),而每一個分片(Slice)包含整數個宏塊(Macroblock),即每片(Slice)至少一個宏塊(Macroblock)。 Slice = Slice Header + Slice Data

在這裏插入圖片描述

  1. 分片頭中包含着分片類型、分片中的宏塊類型、分片幀的數量、分片屬於那個圖像以及對應的幀的設置和參數等信息。
  2. 分片數據中則是宏塊,這裏就是我們要找的存儲像素數據的地方。

有五種分片類型

Slice 內容
I Slice 只包含I宏塊
P Slice 包含P和I宏塊
B Slice 包含B和I宏塊
SP Slice 包含P 和/或 I宏塊,用於不同碼流之間的切換
SI Slice 一種特殊類型的編碼宏塊

宏塊(Macroblock)

宏塊是視頻信息的主要承載者。一個宏塊由一個16×16亮度像素和附加的一個8×8 Cb和一個 8×8 Cr 彩色像素塊組成。每個圖象中,若干宏塊被排列成片的形式。

在這裏插入圖片描述

宏塊分類

宏塊分類 說明
I Macroblock 利用從當前片中已解碼的像素作爲參考進行幀內預測
P Macroblock 利用前面已編碼圖像作爲參考進行幀內預測,一個幀內編碼的宏塊可進一步作宏塊的分割:即16×16.16×8.8×16.8×8亮度像素塊。如果選了8×8的子宏塊,則可再分成各種子宏塊的分割,其尺寸爲8×8,8×4,4×8,4×4
B Macroblock 利用雙向的參考圖像(當前和未來的已編碼圖像幀)進行幀內預測

I,P,B幀與 PTS/DTS

幀的分類 名稱 說明
I幀 幀內編碼幀,又稱intra picture 自身可以通過視頻解壓算法解壓成一張單獨的完整的圖片
P幀 前向預測編碼幀,又稱predictive-frame 需要參考其前面的一個I frame 或者B frame來生成一張完整的圖片
B幀 雙向預測幀,又稱bi-directional interpolated prediction frame 則要參考其前一個I或者P幀及其後面的一個P幀來生成一張完整的圖片
名稱 說明
PTS(Presentation Time Stamp) PTS主要用於度量解碼後的視頻幀什麼時候被顯示出來
DTS(Decode Time Stamp) DTS主要是標識內存中的bit流再什麼時候開始送入解碼器中進行解碼

GOP(Group Of Pictures)

GOP (圖像組)主要用作形容一個 i 幀 到下一個 i 幀之間的間隔了多少個幀。一個I幀所佔用的字節數大於一個P幀,一個P幀所佔用的字節數大於一個B幀。在碼率不變的前提下,GOP值越大,P、B幀的數量會越多,平均每個I、P、B幀所佔用的字節數就越多,也就更容易獲取較好的圖像質量。在遇到場景切換的情況時,H.264編碼器會自動強制插入一個I幀,此時實際的GOP值被縮短了。另一方面,在一個GOP中,P、B幀是由I幀預測得到的,當I幀的圖像質量比較差時,會影響到一個GOP中後續P、B幀的圖像質量,直到下一個GOP開始纔有可能得以恢復,所以GOP值也不宜設置過大。由於P、B幀的複雜度大於I幀,所以過多的P、B幀會影響編碼效率,使編碼效率降低。

IDR(Instantaneous Decoding Refresh)即時解碼刷新

一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。
I和IDR幀都使用幀內預測。I幀不用參考任何幀,但是之後的P幀和B幀是有可能參考這個I幀之前的幀的。IDR就不允許這樣。
比如這種情況:
IDR1 P4 B2 B3 P7 B5 B6 I10 B8 B9 P13 B11 B12 P16 B14 B15 這裏的B8可以跨過I10去參考P7

核心作用:
H.264 引入 IDR 圖像是爲了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數集,開始一個新的序列。這樣,如果前一個序列出現重大錯誤,在這裏可以獲得重新同步的機會。IDR圖像之後的圖像永遠不會使用IDR之前的圖像的數據來解碼。

附錄

將一張圖片轉成 H.264 視頻

ffmpeg -i minimal.png -pix_fmt yuv420p minimal_yuv420.h264

使用 mediainfo 查看 h264 文件信息

➜ mediainfo minimal_yuv420.h264
General
Complete name                            : minimal_yuv420.h264
Format                                   : AVC
Format/Info                              : Advanced Video Codec
File size                                : 1.23 KiB
Duration                                 : 40 ms
Overall bit rate                         : 252 kb/s
Writing library                          : x264 core 157 r2969 d4099dd
Encoding settings                        : cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=2 / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=25 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00

Video
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : High@L1
Format settings                          : CABAC / 4 Ref Frames
Format settings, CABAC                   : Yes
Format settings, Reference frames        : 4 frames
Duration                                 : 40 ms
Width                                    : 64 pixels
Height                                   : 64 pixels
Display aspect ratio                     : 1.000
Frame rate mode                          : Variable
Frame rate                               : 25.000 FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Writing library                          : x264 core 157 r2969 d4099dd
Encoding settings                        : cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=2 / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=25 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00

使用 hexdump 查看二進制數據

➜  hexdump minimal_yuv420.h264
0000000 00 00 00 01 67 64 08 0a ac d9 44 26 84 00 00 03
0000010 00 04 00 00 03 00 c8 3c 48 96 58 00 00 00 01 68
0000020 eb e3 cb 22 c0 00 00 01 06 05 ff ff aa dc 45 e9
0000030 bd e6 d9 48 b7 96 2c d8 20 d9 23 ee ef 78 32 36
0000040 34 20 2d 20 63 6f 72 65 20 31 35 37 20 72 32 39
0000050 36 39 20 64 34 30 39 39 64 64 20 2d 20 48 2e 32
.........

下載測試視頻

要學習 H.264 編碼,就需要有用 H.264 編碼的視頻 demo 來測試,可以用 you-get 工具到主流的一些視頻網站下載個視頻來測試。

test you-get -i https://www.bilibili.com/video/av2650963\?from\=search\&seid\=15782581299335183738
site:                Bilibili
title:               Tribute to Hayao Miyazaki(致敬宮崎駿)
streams:             # Available quality and codecs
    [ DEFAULT ] _________________________________
    - format:        flv
      container:     flv
      quality:       高清 1080P
      size:          42.4 MiB (44452950 bytes)
    # download-with: you-get --format=flv [URL]

    - format:        flv720
      container:     flv
      quality:       高清 720P
      size:          42.4 MiB (44452999 bytes)
    # download-with: you-get --format=flv720 [URL]

    - format:        flv360
      container:     flv
      quality:       流暢 360P
      size:          9.0 MiB (9452072 bytes)
    # download-with: you-get --format=flv360 [URL]test you-get --format=flv360 https://www.bilibili.com/video/av2650963\?from\=search\&seid\=15782581299335183738

視頻格式轉換

視頻格式轉換大部分都可以用 ffmpeg 來實現。

ffmpeg -i input.flv output.mp4

此過程需要對視頻進行重新編碼,比較耗費 CPU 等資源。如果不做轉碼,可以用如下的方式:

ffmpeg -i input.flv -vcodec copy -acodec copy output.mp4

將視頻轉換爲非壓縮的裸視頻

將視頻 input.mp4轉換爲 pix_fmt nv12yuv 的裸視頻 output.yuv, 裸視頻可以作爲後續視頻編碼的 input 。

ffmpeg -i input.mp4 -vcodec rawvideo -vframes 100 -pix_fmt nv12 -an output.yuv

flv 轉 h264

將視頻 input.flv轉換爲 output.h264

ffmpeg -i input.flv -vcodec copy output.h264

mp4 轉 mkv

將視頻 input.mp4轉換爲 output.mkv

ffmpeg -i input.mp4 -vcodec copy -acodec copy output.mkv

參考資料

發佈了10 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章