日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【音视频基础】H264格式分析

發布時間:2023/12/18 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【音视频基础】H264格式分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹

H264是基于運動補償的視頻編碼標準。所謂編碼我的理解就是對數據進行壓縮便于網絡傳輸。而視頻編碼就是依據圖像幀的像素塊之間的相似性對圖像進行壓縮。

相關概念

H264結構中,一幅圖像編碼后的數據叫一幀,一幀由一個或多個Slice片組成,一片由一個或多個MB宏塊組成,一個宏塊由16*16的yuv數據組成。宏塊是H264編碼的基本單位。

幀類型

H264定義了三種幀,I幀,P幀,B幀。

I幀:關鍵幀,幀內壓縮

  • 將全幀圖像進行壓縮編碼傳輸,解碼時只用本身的數據就能重構完整圖像。
  • I幀是一個GOP幀組的第一幀,也是唯一I幀。
  • 描述了圖像背景和運動主體的詳情,不需要參考運動矢量。
  • 因為是全幀壓縮,所以數據量較大,但解碼壓力小。
  • P幀:前向預測編碼幀,幀間壓縮

  • 采用運動補償的方法傳輸本幀與前面的I幀或P幀的差值和運動矢量,所以解碼時也需要參考幀的數據才能重構完整圖像。
  • 只向前參考最靠近的I幀或P幀。
  • 由于是參考幀,所以可能造成解碼錯誤的擴散。
  • 由于是傳輸插值,所以壓縮比較高,解碼壓力較小。
  • B幀:雙向差別幀,幀間壓縮

  • 傳輸本幀與前面的I幀或P幀和后面的P幀的差值和運動矢量,同理解碼時也要參考前后的幀來預測。
  • 壓縮比最高,因為反應了兩個參考幀間運動主體的變化,所以預測比較準確。
  • 不是參考幀(其他幀不會參考B幀進行編碼),不會造成解碼錯誤的擴撒。
  • GOP圖像組

    group of picture 兩個I幀之間的所有幀為一個GOP。

    H264對關聯度高的視頻幀進行分組,其算法是在相鄰幾幅圖像畫面中,一般有差別的像素只有10%以內的點,亮度差值變化不超過2%,而色度差值的變化只有1%以內,我們認為這樣的圖可以分到一組GOP。

    IDR幀:立即刷新圖像

    IDR幀都是I幀,但I幀不一定是IDR幀。當解碼器遇到IDR幀就會清空參考隊列,將已解碼的數據全部輸出或拋棄,開始解碼新的序列。

    而普通的I幀不會清理參考隊列,也就是說IDR可以阻斷誤差的累計,而普通I幀不行。

    PTS. DTS:

    PTS(Presentation Time Stamp):PTS 主要用于度量解碼后的視頻幀什么時候被顯示出來

    DTS(Decode Time Stamp):DTS 主要是標識內存中的 bit 流什么時候開始送入解碼器中進行解碼

    DTS 主要用戶視頻的解碼,在解碼階段使用。PTS主要用于視頻的同步和輸出,在顯示的時候使用。

    由于B幀的存在,要參考前后幀,所以在有B幀的情況下 DTS!=PTS。沒有B幀則兩者相等。

    Vega獲取的信息截圖:

    壓縮技術:

    https://zhuanlan.zhihu.com/p/31056455

    視頻圖像被送到H264編碼器中,編碼器給每一個圖像劃分宏塊。H264默認使用16*16大小作為一個宏塊。但為了更高的壓縮率,還可以將宏塊劃分為8*16、 16*8、 8*8、 4*8、 8*4、 4*4大小的子塊。

    對劃分好的宏塊計算宏塊的像素值。最終一幅圖中每個宏塊都處理完后如下圖:

    處理時間冗余(幀間預測壓縮):

    運動估計與運動補償:

    運動估計:當前幀的某個區域(A)在參考幀中尋找一個合適的匹配區域(B)。

    運動補償:找到區域A和區域B的不同。

    這運動矢量就是炮二的區域移動到炮五的區域,移動后產生一個預測幀。預測幀和當前幀并不完全一樣,他們的區別就是殘差。 此時的殘差則是炮二位置的棋格,以及炮五邊框的顏色變化。

    預測性編碼的產出就是這些運動矢量和殘差,通過這個例子我們能看到這些產出數據是遠遠小于一個完整幀的數據量的。

    處理空間冗余(幀內壓縮):

    https://www.cnblogs.com/charybdis/p/6049108.html

    對于一幅圖像,相鄰的兩個像素的亮度和色度是比較接近的,所以在保存一個像素時不需要將這個像素的全部信息保存,只需要保存這個像素與其參考像素的插值即可。

    使用上一個像素X’做參考像素,經過幀內預測獲得當前像素X的預測像素Xp,X減去Xp就獲得了差值d。

    在解碼的時候,同樣利用X’獲得預測像素Xp,Xp加上插值d,就可以獲取原始值X。

    同時這個X可以作為下一個像素的X’從而成為一個完整的循環。

    當然在H264中,因為以像素為單位太小,所以以宏塊為單位(16*16像素、4*4像素)進行計算。

    上述遺漏的問題,預測值Xp怎么來的?Xp是通過X’利用某個公式計算的。在白皮書中 4*4 有9種預測模式,16*16有4種預測模式。

  • 第一列所有的像素都用A像素值,第二列所有的像素都用B像素值,依次類推。
  • 第一行所有的像素都用I像素值,依次類推。
  • 16個像素等于ABCDIJKL這個八個像素的平均值。
  • a = (A+2B+C+2)/4,這里+2是為了四舍五入。b和e = (B+2C+D)/4。c、f、i=(C+2D+E+2)/4,d、g、j、m=(D+2E+F+2)/4。h、k、n=(E+2F+G+2)/4。l、o=(F+2G+H+2)/4。p=(G+2H+H+2)/4=(G+3H+2)/4
  • 8都是通過與3類似的算法計算得到。
  • 如何在這9種算法種選擇,當然是希望誤差越小越好,所以也有對應的算法去計算誤差。例如:SAD,SATD等。

    同時因為選擇了不同的算法,所以解碼器也需要知道每個宏塊具體使用哪種算法。所以有1bit用于保存是由與上一個一樣,如果不一樣則用4bit保存具體選擇哪個算法。

    X’真的與原始X完全一樣么?

    理論上上講按前面的算法應該是一樣的,但因為差值傳到解碼器的過程種經過了量化、變換、反變換和反量化,有了精度算是,因此X’真的與原始X無法完全一致。

    H264編解碼流程:

    H264分層結構

    H264的主要目標是為了有高視頻壓縮比和良好的網絡親和性。

    為了這兩個目的H264將系統架構劃分了兩個層面 VCL 和 NAL。

    VCL:Video Coding Layer,視頻編碼層

    對核心算法引擎、塊、宏塊及片的語法級別的定義,負責有效表示視頻數據的內容,最終輸出編碼完的數據SODB(數據比特串)

    NAL:Network Abstraction Layer,網絡提取層

    定義了片級以上的語法級別(如序列參數集和圖像參數集),負責以網絡所要求的恰當方式去格式化數據并提供頭信息,以保證數據適合各種信道和存儲介質上的傳輸

    『NAL』就是為了包裝『VCL』以達到更好網絡傳輸效果。NAL層將 SODB 打包成 RBSP(原始字節序列負荷) 然后加上NAL header 組成一個NALU。

    RBSP(Raw Byte Sequence Payload,原始字節序列載荷):

    PBSP就是在SODB后添加了trailing bits,即一個bit 1和若干個bit 0,以便字節對齊。

    傳統的視頻碼流僅有VCL視頻編碼層,而H264可以根據不同應用增加不同的NAL header,用來適應不同的網絡應用環境,減少碼流的傳輸錯誤。VCL數據在傳輸前先被映射到NAL單元中。

    EBSP:(Encapsulated Byte Sequence Payload, 擴展字節序列載荷)

    H264規定,當檢測到當檢測到0x000000時,也可以表示當前NALU的結束。

    那這樣就會產生一個問題,就是如果在NALU的內部,出現了0x000001或0x000000時該怎么辦?

    在編碼時,每遇到兩個字節連續為0(0x0000),就插入一個字節的0x03。解碼時將0x03去掉。

    H264碼流結構(Annex-B格式)

    ps:H264有兩種封裝:?種是annexb模式,傳統模式,有startcode。?種是mp4模式,?般mp4,mkv都是mp4模式,沒有startcode,SPS和PPS以及其它信息被封裝在container中,每?個frame前?4個字節是這個frame的?度很多解碼器只?持annexb這種模式。

    H264碼流是一個個連續的NALU,一個NALU包含 [NALU Header][NALU Payload (RBSP)] 三部分。

    StartCode:是一個NALU單元開始。

    主要是為了將相鄰兩個NALU劃分開,讓他們有一個界線,方便解碼。必須是 0x00 00 00 01 或者0x00 00 01。

    那么玩意數據中間正好有個 0x00 00 00 01 或者 0x00 00 01 怎么辦?見上述EBSP。

    并且h264有個防止競爭的機制,在編碼一個NAL時,如果出現有連續兩個0x00字節,就在連續兩個0x00后面插入一個0x03(解碼的時候這個0x03會被丟棄)。

    NAL header:定義了RBSP單元的類型

    由 1字節(8位)組成。禁止位(1位)、重要性指示位(2位)、NALU類型(5位)。

    nal_unit_type取值說明:

    SPS 和 PPS

    https://zhuanlan.zhihu.com/p/27896239

    從上圖可知SPS和PPS是一個NALU的類型。

    實際網絡傳輸編碼好的數據流的時候會出現丟包,而如果丟包數據為圖像頭等關鍵信息的時候甚至會導致后續解碼失敗。在H264之前,為了應對圖像頭關鍵信息被丟失的做法是在很多包(也有說法是每一個包)都會攜帶圖像頭關鍵信息(冗余做災備的思想)。但是,在H264種,為了提高網絡傳輸魯棒性,重新設計出SPS和PPS。

    SPS(序列參數集):SPS中保存了一組編碼視頻序列(Coded Video Sequence)的全局參數。因此該類型保存的是和編碼序列相關的參數。

    https://yinwenjie.blog.csdn.net/article/details/52771030

    PPS(圖像參數集):PPS中保存了整體圖像相關的參數。

    https://yinwenjie.blog.csdn.net/article/details/52877689

    根據Vega分析,IDR幀中就包含了SPS,PPS和IDR本身的NALU。

    SEI:補充增強信息

    Access Unit分隔符:Access Unit:是一個或者多個 NALU 的集合,代表了一個完整的幀。

    H264碼流整體結構:

    Level

    通過 Vega 分析,不同的 H264 文件有不用的 Profile 和 level。

    計算支持1080P(1920*1080)的最低級別:

    一個宏塊大小16*16.。ceil是向上取整

    水平宏塊數(PicWidthInMbs)= ceil(視頻寬度 / 16) = ceil(1080 / 16) = ceil(67.5) = 68

    垂直宏塊數(FrameHeightInMbs)= ceil(視頻寬度 / 16) = ceil(1920 / 16) = ceil(120) = 120

    每幀宏塊數(Macroblocks per frame)= 水平宏塊數 * 垂直宏塊數 = 68 * 120 = 8160

    查詢上面的級別詳表可知,支持每幀8160個宏塊的最低級別是4。

    級別4 允許的每秒最大宏塊數是 245,760 。所以 245760 / 8160 =30.1,即最高支持每秒30.1幀。當然級別更高支持的幀數也更多。

    MaxDpbMbs

    表中最后一列為 MaxDpbMbs 最大解碼緩沖區宏塊數。也就是解碼時參考緩沖區中的宏塊數。

    DpbMbs = ref(參考幀數) * PicWidthInMbs(水平宏塊數) * FrameHeightInMbs(垂直宏塊數)
    我們可以根據 MaxDpbMbs 倒推出 最大參考幀數。

    公式為:max_ref = min(floor(MaxDpbMbs / (PicWidthInMbs * FrameHeightInMbs)), 16)。floor是向下取整。

    以1080P + Level 4 為例:

    min(floor(32,768 / (68*120)),16) = 4 注:后面的16 是因為 參考幀數組大只能為16

    所以1080P的視頻在 Level 4 級別下,最高支持 4 個參考幀。

    反推可知,在解碼時參考幀的幀數并不只是前1幀,而是前多幀。同理編碼時當前幀的參考幀也不只是前一幀,而是前多幀。

    這也就應證了I幀和IDR幀的區別。雖然應證了,但還是存在疑問,既然I幀已經可以獨立編碼解碼了,那么為什么在編碼解碼的時候還要參考I幀之前的幀?

    總結

    以上是生活随笔為你收集整理的【音视频基础】H264格式分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。