H264碼流中SPS PPS詳解<轉>


  • 轉載地址:https://zhuanlan.zhihu.com/p/27896239
  • 1 SPS和PPS從何處而來?
  • 2 SPS和PPS中的每個參數起什么作用?
  • 3 如何解析SDP中包含的H.264的SPS和PPS串?

1 客戶端抓包

在做客戶端視頻解碼時,一般都會使用Wireshark抓包工具對接收的H264碼流進行分析,如下所示:

在這里我們可以看到對解碼視頻起關鍵作用的SPS和PPS。

雙擊SPS內容如下:

雙擊PPS內容如下:

那么從上面的sps中我們知道圖像的寬,高。

寬=(19+1 )*16=320

高=(14+1)*16=240

為什么?參考下面

2 SPS PPS詳解

2.1 SPS語法元素及其含義

在H.264標准協議中規定了多種不同的NAL Unit類型,其中類型7表示該NAL Unit內保存的數據為Sequence Paramater Set。在H.264的各種語法元素中,SPS中的信息至關重要。如果其中的數據丟失或出現錯誤,那么解碼過程很可能會失敗。SPS及后續將要講述的圖像參數集PPS在某些平台的視頻處理框架(比如iOS的VideoToolBox等)還通常作為解碼器實例的初始化信息使用。

SPS即Sequence Paramater Set,又稱作序列參數集。SPS中保存了一組編碼視頻序列(Coded video sequence)的全局參數。所謂的編碼視頻序列即原始視頻的一幀一幀的像素數據經過編碼之后的結構組成的序列。而每一幀的編碼后數據所依賴的參數保存於圖像參數集中。一般情況SPS和PPS的NAL Unit通常位於整個碼流的起始位置。但在某些特殊情況下,在碼流中間也可能出現這兩種結構,主要原因可能為:

  • 解碼器需要在碼流中間開始解碼;
  • 編碼器在編碼的過程中改變了碼流的參數(如圖像分辨率等);

在做視頻播放器時,為了讓后續的解碼過程可以使用SPS中包含的參數,必須對其中的數據進行解析。其中H.264標准協議中規定的SPS格式位於文檔的7.3.2.1.1部分,如下圖所示:

 

其中的每一個語法元素及其含義如下:

(1) profile_idc:

標識當前H.264碼流的profile。我們知道,H.264中定義了三種常用的檔次profile:

基准檔次:baseline profile;

主要檔次:main profile;

擴展檔次:extended profile;

在H.264的SPS中,第一個字節表示profile_idc,根據profile_idc的值可以確定碼流符合哪一種檔次。判斷規律為:

profile_idc = 66 → baseline profile;

profile_idc = 77 → main profile;

profile_idc = 88 → extended profile;

在新版的標准中,還包括了High、High 10、High 4:2:2、High 4:4:4、High 10 Intra、High 4:2:2 Intra、High 4:4:4 Intra、CAVLC 4:4:4 Intra等,每一種都由不同的profile_idc表示。

另外,constraint_set0_flag ~ constraint_set5_flag是在編碼的檔次方面對碼流增加的其他一些額外限制性條件。

在我們實驗碼流中,profile_idc = 0x42 = 66,因此碼流的檔次為baseline profile。

(2) level_idc

標識當前碼流的Level。編碼的Level定義了某種條件下的最大視頻分辨率、最大視頻幀率等參數,碼流所遵從的level由level_idc指定。

當前碼流中,level_idc = 0x1e = 30,因此碼流的級別為3。

(3) seq_parameter_set_id

表示當前的序列參數集的id。通過該id值,圖像參數集pps可以引用其代表的sps中的參數。

(4) log2_max_frame_num_minus4

用於計算MaxFrameNum的值。計算公式為MaxFrameNum = 2^(log2_max_frame_num_minus4 + 4)。MaxFrameNum是frame_num的上限值,frame_num是圖像序號的一種表示方法,在幀間編碼中常用作一種參考幀標記的手段。

(5) pic_order_cnt_type

表示解碼picture order count(POC)的方法。POC是另一種計量圖像序號的方式,與frame_num有着不同的計算方法。該語法元素的取值為0、1或2。

(6) log2_max_pic_order_cnt_lsb_minus4

用於計算MaxPicOrderCntLsb的值,該值表示POC的上限。計算方法為MaxPicOrderCntLsb = 2^(log2_max_pic_order_cnt_lsb_minus4 + 4)。

(7) max_num_ref_frames

用於表示參考幀的最大數目。

(8) gaps_in_frame_num_value_allowed_flag

標識位,說明frame_num中是否允許不連續的值。

(9) pic_width_in_mbs_minus1

用於計算圖像的寬度。單位為宏塊個數,因此圖像的實際寬度為:

frame_width = 16 × (pic\_width\_in\_mbs_minus1 + 1);

(10) pic_height_in_map_units_minus1

使用PicHeightInMapUnits來度量視頻中一幀圖像的高度。PicHeightInMapUnits並非圖像明確的以像素或宏塊為單位的高度,而需要考慮該宏塊是幀編碼或場編碼。PicHeightInMapUnits的計算方式為:

PicHeightInMapUnits = pic\_height\_in\_map\_units\_minus1 + 1;

(11) frame_mbs_only_flag

標識位,說明宏塊的編碼方式。當該標識位為0時,宏塊可能為幀編碼或場編碼;該標識位為1時,所有宏塊都采用幀編碼。根據該標識位取值不同,PicHeightInMapUnits的含義也不同,為0時表示一場數據按宏塊計算的高度,為1時表示一幀數據按宏塊計算的高度。

按照宏塊計算的圖像實際高度FrameHeightInMbs的計算方法為:

FrameHeightInMbs = ( 2 − frame_mbs_only_flag ) * PicHeightInMapUnits

(12) mb_adaptive_frame_field_flag

標識位,說明是否采用了宏塊級的幀場自適應編碼。當該標識位為0時,不存在幀編碼和場編碼之間的切換;當標識位為1時,宏塊可能在幀編碼和場編碼模式之間進行選擇。

(13) direct_8x8_inference_flag

標識位,用於B_Skip、B_Direct模式運動矢量的推導計算。

(14) frame_cropping_flag

標識位,說明是否需要對輸出的圖像幀進行裁剪。

(15) vui_parameters_present_flag

標識位,說明SPS中是否存在VUI信息。

2.2 PPS語法元素及其含義

除了序列參數集SPS之外,H.264中另一重要的參數集合為圖像參數集Picture Paramater Set(PPS)。通常情況下,PPS類似於SPS,在H.264的裸碼流中單獨保存在一個NAL Unit中,只是PPS NAL Unit的nal_unit_type值為8;而在封裝格式中,PPS通常與SPS一起,保存在視頻文件的文件頭中。

在H.264的協議文檔中,PPS的結構定義在7.3.2.2節中,具體的結構如下表所示:

其中的每一個語法元素及其含義如下:

(1) pic_parameter_set_id

表示當前PPS的id。某個PPS在碼流中會被相應的slice引用,slice引用PPS的方式就是在Slice header中保存PPS的id值。該值的取值范圍為[0,255]。

(2) seq_parameter_set_id

表示當前PPS所引用的激活的SPS的id。通過這種方式,PPS中也可以取到對應SPS中的參數。該值的取值范圍為[0,31]。

(3) entropy_coding_mode_flag

熵編碼模式標識,該標識位表示碼流中熵編碼/解碼選擇的算法。對於部分語法元素,在不同的編碼配置下,選擇的熵編碼方式不同。例如在一個宏塊語法元素中,宏塊類型mb_type的語法元素描述符為“ue(v) | ae(v)”,在baseline profile等設置下采用指數哥倫布編碼,在main profile等設置下采用CABAC編碼。

標識位entropy_coding_mode_flag的作用就是控制這種算法選擇。當該值為0時,選擇左邊的算法,通常為指數哥倫布編碼或者CAVLC;當該值為1時,選擇右邊的算法,通常為CABAC。

(4) bottom_field_pic_order_in_frame_present_flag

標識位,用於表示另外條帶頭中的兩個語法元素delta_pic_order_cnt_bottom和delta_pic_order_cn是否存在的標識。這兩個語法元素表示了某一幀的底場的POC的計算方法。

(5) num_slice_groups_minus1

表示某一幀中slice group的個數。當該值為0時,一幀中所有的slice都屬於一個slice group。slice group是一幀中宏塊的組合方式,定義在協議文檔的3.141部分。

(6) num_ref_idx_l0_default_active_minus1、num_ref_idx_l0_default_active_minus1

表示當Slice Header中的num_ref_idx_active_override_flag標識位為0時,P/SP/B slice的語法元素num_ref_idx_l0_active_minus1和num_ref_idx_l1_active_minus1的默認值。

(7) weighted_pred_flag

標識位,表示在P/SP slice中是否開啟加權預測。

(8) weighted_bipred_idc

表示在B Slice中加權預測的方法,取值范圍為[0,2]。0表示默認加權預測,1表示顯式加權預測,2表示隱式加權預測。

(9) pic_init_qp_minus26和pic_init_qs_minus26

表示初始的量化參數。實際的量化參數由該參數、slice header中的slice_qp_delta/slice_qs_delta計算得到。

(10) chroma_qp_index_offset

用於計算色度分量的量化參數,取值范圍為[-12,12]。

(11) deblocking_filter_control_present_flag

標識位,用於表示Slice header中是否存在用於去塊濾波器控制的信息。當該標志位為1時,slice header中包含去塊濾波相應的信息;當該標識位為0時,slice header中沒有相應的信息。

(12) constrained_intra_pred_flag

若該標識為1,表示I宏塊在進行幀內預測時只能使用來自I和SI類型宏塊的信息;若該標識位0,表示I宏塊可以使用來自Inter類型宏塊的信息。

(13) redundant_pic_cnt_present_flag

標識位,用於表示Slice header中是否存在redundant_pic_cnt語法元素。當該標志位為1時,slice header中包含redundant_pic_cnt;當該標識位為0時,slice header中沒有相應的信息。

3 解析SDP中包含的H.264的SPS和PPS串

用RTP傳輸H264的時候,需要用到sdp協議描述,其中有兩項:Sequence Parameter Sets (SPS) 和Picture Parameter Set (PPS)需要用到,那么這兩項從哪里獲取呢?答案是從H264碼流中獲取.在H264碼流中,都是以"0x00 0x00 0x01"或者"0x00 0x00 0x00 0x01"為開始碼的,找到開始碼之后,使用開始碼之后的第一個字節的低5位判斷是否為7(sps)或者8(pps), 及data[4] & 0x1f == 7 || data[4] & 0x1f == 8.然后對獲取的nal去掉開始碼之后進行base64編碼,得到的信息就可以用於sdp.sps和pps需要用逗號分隔開來.

SDP中的H.264的SPS和PPS串,包含了初始化H.264解碼器所需要的信息參數,包括編碼所用的profile,level,圖像的寬和高,deblock濾波器等。

由於SDP中的SPS和PPS都是BASE64編碼形式的,不容易理解,有一個工具軟件可以對SDP中的SPS和PPS進行解析,下載地址:

用法是在命令行中輸入:

spsparser sps.txt pps.txt output.txt

例如sps.txt中的內容為:

Z0LgFNoFglE=

pps.txt中的內容為:

aM4wpIA=

最終解析得到的結果為:

這里需要特別提一下這兩個參數

pic_width_in_mbs_minus1 = 21

pic_height_in_mbs_minus1 = 17

分別表示圖像的寬和高,以宏塊(16x16)為單位的值減1

因此,實際的寬為 (21+1)*16 = 352 高為 (17+1)*16 = 288

到這里應該知道第一部分客戶端抓包計算圖像寬高遺留下來的問題了吧。

Reference:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM