H264學習

最近在給MP4文件作CENC加密時須要解析H264的slice頭部,才發現對於H264的一些基本概念沒有搞清楚。小小的記錄一下:html

 

1. 如何判斷一個H264的幀類型。幀類型包括IDR/I/P/B.網絡

   看一下標準的描述:post

nal_unit( NumBytesInNALunit )
{
  forbidden_zero_bit All                              f(1)
  nal_ref_idc                                    u(2)
  nal_unit_type                                   u(5)
  NumBytesInRBSP = 0
  for( i = 1; i < NumBytesInNALunit; i++ )
  {
    if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 )
    {
      rbsp_byte[ NumBytesInRBSP++ ]                      b(8)
      rbsp_byte[ NumBytesInRBSP++ ]                      b(8)
      i += 2
      emulation_prevention_three_byte /* equal to 0x03 */         f(8)
    }
    else
      rbsp_byte[ NumBytesInRBSP++ ]                      b(8)
  }
}學習

 第一個byte中的後5位 NAL_UNIT_TYPE 標誌了幀類型。標準裏幀類型的描述爲:編碼

   在這張表裏,區分了IDR幀和非IDR幀類型。NAL_UNIT_TYPE=5即IDR幀, 可是非IDR幀中I/P/B幀的類型並無明顯的區分。查看了一些H264文件,發現I/P/B幀的NAL_UNIT_TYPE一般爲1,也就是「Coded slice of a non-IDR picture」。看來經過NAL_UNIT_TYPE是沒法完全區分幀類型了,事實上也是。對於H264幀類型,必須解析到Slice層。加密

   NAL_UNIT_TYPE等於1,2,5時是存在 slice_header頭的。NAL_UNIT_TYPE爲2,3,4的區別見下一節。url

   slice頭的結構以下:spa

slice_header( )
{ 
        first_mb_in_slice                     ue(v)  
        slice_type                            ue(v)  
        pic_parameter_set_id                  ue(v)  
        frame_num                             u(v)  
        if( !frame_mbs_only_flag ) 
        {     
                field_pic_flag                u(1)   
                if( field_pic_flag )      
                    bottom_field_flag         u(1)  
        }    
        if( nal_unit_type  = =  5 ) 
            idr_pic_id                        ue(v)  
        ....
}

     Slice的類型,見下圖:.net

  一、I宏塊是指每一個塊或宏塊是經過其所在的Slice中的以前的已經編碼過的數據進行預測的;
  二、P宏塊是指宏快或宏塊分割是經過List0中的一個參考圖像來進行預測的;
  三、B宏塊是指宏快或宏塊分割是經過List0和/或List1中的參考圖像來進行預測的;
  四、SI和SP:即Switch I和Switch P,是一種特殊的編解碼條帶,能夠保證在視頻流之間進行有效的切換,而且解碼器能夠任意的訪問。好比,同一個視頻源被編碼成各類碼率的碼流,在傳輸的過程當中能夠根據網絡環境進行實時的切換;
  五、SI宏塊是一種特殊類型的內部編碼宏塊,按Intra_4x4預測宏塊編碼。3d

      Slice類型對應的slice_type值,見下圖:  

     在上圖中,I/SI條帶的值包括2,4,7,9。 P條帶包括0,3,5,8。B條帶包括1,6。

     可能會感受有些奇怪,0到4與5到9竟然是重複的。答案是這樣的,slice_type的值在5到9的範圍內表示,除了當前條帶的編碼類型,全部當前編碼圖像的其餘條帶的slice_type的值應與當前條帶的slice_type的值同樣,或者等於當前條帶的slice_type的值減5。

     回到問題的原點,如何判斷I/P/B。

     首先判斷NALU類型是不是5,若是是,那麼之後連續出現的NALU類型爲5的NALU就屬於 IDR 幀(一種特殊的 I 幀);

     若是NALU不是5,則要進一步判斷 slice_type 是不是 7, 若是是, 那麼連續出現的 slice_type=7的slice 就屬於 I 幀; 若是 slice_type=2,那麼就要判斷與當前 slice 同屬一幀的 slice 是否都是 I slice, 若是都是, 那麼這些 slice 就屬於一個 I 幀。

     碼流中通常不會出現複雜的狀況,粗略的判斷標準就是 slice_type  是否等於2或7。

 

2. 編碼條帶數據分割塊A/B/C區別

    我查了幾個h264文件,沒有在實際中發現這幾種類型。

     如下直接引用自

   H264標準句法表中C的含義理解

     編碼條帶數據分割塊A slice_data_partition_a_layer_rbsp( )
  編碼條帶數據分割塊B slice_data_partition_b_layer_rbsp( )
  編碼條帶數據分割塊C slice_data_partition_c_layer_rbsp( )
  這是3種對於片數據的處理方式,其中2類型時,只傳遞片中最重要的信息,如片頭,片中宏塊的預測模式等,3類型是隻傳輸殘差,而4時則只能夠傳輸殘差中的AC係數。

  對照句法表能夠看到經過C中指定的數字值,限定了在各個句法元素在特定NAL類型中的使用,以達到在特定NAL中使用不一樣的句法元素,如不在4中傳輸殘差的DC值,見畢書---表7.17中DC係數語法後面爲3,而AC係數後面爲3|4,這就達到了在 編碼條帶數據分割塊B 中能夠傳輸全部殘差,而在編碼條帶數據分割塊C中僅能夠傳輸AC殘差。

  據此能夠獲得下面的結論:

    C是語法元素能夠出如今哪一種NAL中的指示,NAL的類型由nal_type_unit指定

  

 參考:

 1. h264 NAL頭解析

 2. h264 圖像、幀、片、NALU

 3. 從Slice_Header學習H.264(一)--片頭語法元素介紹

相關文章
相關標籤/搜索