《H.264/AVC視訊編解碼技術詳解》視訊教程已經在“CSDN學院”上線,視訊中詳述了H.264的背景、標準協議和實現,並通過一個實戰工程的形式對H.264的標準進行解析和實現,歡迎觀看!

“紙上得來終覺淺,絕知此事要躬行”,只有自己按照標準文件以程式碼的形式操作一遍,才能對視訊壓縮編碼標準的思想和方法有足夠深刻的理解和體會!

GitHub程式碼地址:點選這裡

在H.264標準協議中規定了多種不同的NAL Unit型別,其中型別7表示該NAL Unit內儲存的資料為Sequence Paramater Set。在H.264的各種語法元素中,SPS中的資訊至關重要。如果其中的資料丟失或出現錯誤,那麼解碼過程很可能會失敗。SPS及後續將要講述的影象引數集PPS在某些平臺的視訊處理框架(比如iOS的VideoToolBox等)還通常作為解碼器例項的初始化資訊使用。

1. 什麼是SPS

如上文所述,SPS即Sequence Paramater Set,又稱作序列引數集。SPS中儲存了一組編碼視訊序列(Coded video sequence)的全域性引數。所謂的編碼視訊序列即原始視訊的一幀一幀的畫素資料經過編碼之後的結構組成的序列。而每一幀的編碼後資料所依賴的引數保存於影象引數集中。

在簡單的H.264編解碼的Demo(例如本系列博文、課程所做的SimpleH264Analyzer工程)中,一個SPS和PPS的NAL Unit通常位於整個碼流的起始位置。但在某些特殊情況下,在碼流中間也可能出現這兩種結構,主要原因可能為:

  1. 解碼器需要在碼流中間開始解碼;
  2. 編碼器在編碼的過程中改變了碼流的引數(如影象解析度等);

2. SPS的結構

在我們這個例項中,SPS NAL Unit中的二進位制內容為:

42 00 1e e8 58 58 98 80

為了讓後續的解碼過程可以使用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資訊。

.