H264幀型別判斷
我們經常在網路直播推流或者客戶端拉流的時候,需要對獲取到的H.264視訊幀進行判斷後處理,我們經常獲取到各種不同的視訊資料0x67 0x68 0x65 0x61,0x27 0x28 0x25 0x21,0x47 0x48 0x45 0x41,各種不同的編碼晶片有時間出來的NAL Header規則不大一樣,那麼我們怎麼來以統一的方式判斷幀的型別呢:sps、pps、IDR、P
H264
H264在網路傳輸的是NALU,NALU的結構是:NAL頭+RBSP,實際傳輸中的資料流如圖所示:
其中NAL頭佔一個位元組,其低5個bit位表示NAL type,具體如下表:
NAL type | NAL型別 |
---|---|
0 | 未使用 |
1 | 非IDR的片 |
2 | 片資料A分割槽 |
3 | 片資料B分割槽 |
4 | 片資料C分割槽 |
5 | IDR影象的片 |
6 | 補充增強資訊單元(SEI) |
7 | 序列引數集(SPS) |
8 | 影象引數集(PPS) |
9 | 分界符 |
10 | 序列結束 |
11 | 碼流結束 |
12 | 填充 |
13..23 | 保留 |
24..31 | 不保留 |
RBSP 為原始位元組序列載荷。
NAL type為5,則此幀為I幀即關鍵幀,type為1時為非關鍵幀(P幀…)。 在實際的H264資料幀中,往往幀NAL type前面帶有00 00 00 01 或 00 00 01分隔符,一般來說編碼器編出的首幀資料為PPS與SPS,接著為I幀,然後是P幀…
SPS部分 1. NALU起始符為00 00 00 01。 2. 緊跟著起始符的是是Start code,如 00 00 00 01 0x67(start coe)
0x67的二進位制是0110 0111, 以0x67為例分析如下(u: 0110 0111): 1. forbidden_zero_bit 是禁止位,應該是第一位即u(1) = 0,1為語法有錯誤 2. nal_ref_idc是參考級別,代表被其它幀參考情況,u(2) = 11 = 3(Nal_ref_idc表示NAL的優先順序,0-3, 取值越大,表示當前NAL越重要,如果當前NAL是屬於參考幀的片,或是序列引數集,或是影象引數集這些重要單位時,取值必須>0) 3. nal_unit_type是該幀的型別,為剩下的5位,u(5) = 0 0111 = 7 目前型別有: H264定義的型別 values for nal_unit_type typedef enum { NALU_TYPE_SLICE = 1, NALU_TYPE_DPA = 2, NALU_TYPE_DPB = 3, NALU_TYPE_DPC = 4, NALU_TYPE_IDR = 5, NALU_TYPE_SEI = 6, NALU_TYPE_SPS = 7, NALU_TYPE_PPS = 8, NALU_TYPE_AUD = 9, NALU_TYPE_EOSEQ = 10, NALU_TYPE_EOSTREAM = 11, NALU_TYPE_FILL = 12, (#)if (MVC_EXTENSION_ENABLE) NALU_TYPE_PREFIX = 14, NALU_TYPE_SUB_SPS = 15, NALU_TYPE_SLC_EXT = 20, NALU_TYPE_VDRD = 24 // View and Dependency Representation Delimiter NAL Unit (#)endif } NaluType; 可以看出7是NALU_TYPE_SPS 即sequence parameter sets
3.start code後面緊跟著的是profile_idc, 如00 00 00 01 0x67 0x64(profile_idc)
0x64轉化為十進位制則是100, H264定義如下: 66 Baseline 77 Main 88 Extended 100 High (FRExt) 110 High 10 (FRExt) 122 High 4:2:2 (FRExt) 144 High 4:4:4 (FRExt) 所以0x64是100 表示high_profile, High (FRExt)
參考: 00 00 00 01 67 42 00 28 E9 00 A0 0B 77 FE 00 02 00 03 C4 80 00 00 03 00 80 00 00 1A 4D 88 10 94 00 00 00 01 00 00 00 01為NALu頭,其餘碼流由十六進位制轉為二進位制 67 0110 0111 42 0100 0010 00 0000 0000 28 0010 1000 E9 1110 1001 00 0000 0000 A0 1010 0000 0B 0000 1011 77 0111 01/11 …… 94 1001 01//00 說明: “/”後的碼流要對照標準中AnnexE的句法表,是VUI(VideoUsabilityInformation?)的內容, 不懂,不寫了,只寫SPS部分先。 “//”後面兩個0是補齊用的。 NAL層句法:碼,值 forbidden_zero_bit(f(1)):0,0 nal_ref_idc(u(2)):11, 3 nal_unit_type(u(5)): 0 0111, 7, SPS SPS序列引數集的句法:碼,值 profile_idc(u(8)) = 0100 0010,66 , baseline profile基礎檔次 constraint_set0_flag(u(1)):0,0 constraint_set1_flag(u(1)):0,0 constraint_set2_flag(u(1)):0,0 constraint_set3_flag(u(1)):0,0 reserved_zero_4bits(u(4)):0000,0 level_idc(u(8)) :00101000,40 ,級別 seq_parameter_set_id(ue(v)): 1, 0 log2_max_frame_num_minus4(ue(v): 1, 0 MaxFrameNum = 2^(0+4) = 16 pic_order_cnt_type(ue(v)):1, 0 log2_max_pic_order_cnt_lsb_minus4(ue(v)):010 ,1 MaxPicOrderCntLsb = 2^(1+4) = 32 num_ref_frames(ue(v)):010, 1 gaps_in_frame_num_value_allowed_flag(u(1)):0,0 pic_width_in_mbs_minus1(ue(v)): 0000001010000, 2^6-1+16 = 79 PicWidthInMbs = pic_width_in_mbs_minus1 + 1 = 80 pic_height_in_map_units_minus1(ue(v)): 00000101101 ,2^5-1+13 = 44 PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1 =45 frame_mbs_only_flag(u(1)):1,1 direct_8x8_inference_flag(u(1)): 1,1 frame_cropping_flag(u(1)):0,0 vui_parameters_present_flag(u(1)):1 ,1 這個引數為1,說明下面的句法存在 vui_parameters( ) aspect_ratio_info_present_flag(u(1)):1
其中: pic_width_in_mbs_minus1 : 79 pic_height_in_map_units_minus1 : 44 (79+1)x16=1280 (44+1)x16=720