1. 程式人生 > >H264—幀,片,引數集,NALU等概念

H264—幀,片,引數集,NALU等概念

h264是一個編碼壓縮的格式,可以使用x264庫進行編碼,原始碼開放,可下載編譯使用。

-------------------------------------------------------------------------------------------------------------

H.264 Codec

h264概念上區分視訊編碼層(VCL)和網路抽象層(NAL).

VCL包含Codec的信令處理功能;以及如轉換,量化,運動補償預測機制;以及迴圈過濾器。他遵從今天大多數視訊codec的一般概念,基於巨集快的編碼器,使用基於運動補償的影象間預測和殘餘訊號的轉換編碼。

(NAL)編碼器封裝VCL編碼器輸出的片斷到網路抽象層單元(NAL units),它適合於通過包網路傳輸或用於面向包的多路複用環境。

-------------------------------------------------------------------------------------------------------------

網路抽象層單元(NALU)型別

NAL單元型別位元組格式如下:
    
      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|  Type   |
      +---------------+
 
   NAL單元型別位元組部件的語義在H.264規範中制定, 簡要描述如下.
 
   F: 1 bit
      forbidden_zero_bit.  H.264規範宣告設定為1指示語法違例。
 
   NRI: 2 bits
      nal_ref_idc.  00值指示NAL單元的不用於幀間影象預測的重構參考影象。這樣的NAL單元可以被丟棄而不用冒參考
      影象完整性的風險。大於0的值指示NAL單元的解碼要求維護參考影象的完整性。
 
   Type: 5 bits
      nal_unit_type.  本部件指定NAL單元荷載型別定義在[1]的表 7-1中和本文後面。為了參考所有當前定義的NAL單元型別
      和他們的語義

  • 0:未規定
  • 1:非IDR影象中不採用資料劃分的片段
  • 2:非IDR影象中A類資料劃分片段
  • 3:非IDR影象中B類資料劃分片段
  • 4:非IDR影象中C類資料劃分片段
  • 5:IDR影象的片段
  • 6:補充增強資訊(SEI)
  • 7:序列引數集(SPS)
  • 8:影象引數集(PPS)
  • 9:分割符
  • 10:序列結束符
  • 11:流結束符
  • 12:填充資料
  • 13:序列引數集擴充套件
  • 14:帶字首的NAL單元
  • 15:子序列引數集
  • 16 – 18:保留
  • 19:不採用資料劃分的輔助編碼影象片段
  • 20:編碼片段擴充套件
  • 21 – 23:保留
  • 24 – 31:未規定
在實際的H264資料幀中,往往幀前面帶有00 00 00 01 或 00 00 01分隔符,一般來說編碼器編出的首幀資料為PPS與SPS,接著為IDR幀(關於IDR與I的區別http://blog.csdn.net/jammg/article/details/52357245

比如,將rgb轉換轉換成yuv後(x264只支援將yuv編碼壓縮),使用x264編碼器編碼出的264檔案前面一般是這樣:

00 00 00 01 67 ....(sps)....... 00 00 00 01 68 .........(pps)....... 00 00 00 01 65 ......(IDR)...........

[由於NAL的語法中沒有給出長度資訊,實際的傳輸、儲存系統需要增加額外的頭實現各個NAL單元的定界。]

-------------------------------------------------------------------------------------------------------------

引數集概念(SPS/PPS)
 
   H.264一個非常基本的設計概念是產生自包含包, 使得如RFC2429的頭重複或MPEG-4的頭擴充套件編碼(HEC)[11]機制變得不必要。
   這是通過從媒體流解耦合不止一個片斷的相對資訊來實現的。高層meta資訊應該可靠/非同步的傳送,事先不和包含片斷包的RTP
   包流傳送。(對於沒有通過帶外傳輸通道傳送本資訊的應用,通過帶內傳送本資訊也提供了手段)。高層引數的組合被稱為引數集。
   H.264規範包括兩類引數集:順序引數集和影象引數集。一個活動順序引數集在一個編碼視訊序列中保持不變,一個活動影象引數集
   在一個編碼影象裡保持不變。順序和影象引數集結構包含如影象大小,採用的可選的編碼模式,巨集塊到片斷組對映等資訊。
 
   為了改變影象引數(如影象大小)而不用同步傳送引數集修改給片斷包流,編碼器和解碼器可以維護不止一個順序和影象引數集的
   列表。每個片斷頭包含一個碼字指示使用的順序和影象引數集。
 
   本機制允許從包流中解耦合引數集的傳輸,通過外部手段傳輸他們(即,作為能力交換的副作用),或通過一個(可靠或不可靠)控制協議
   他們從沒有被傳送但是被應用設計規範修復甚至是可能的。

幀(frame)與 片(slice)

-------------------------------------------------------------------------------------------------------------

大小關係

對於 H.264中出現的一些概念從大到小排序依次是:序列、影象(大多時候稱為幀,包括I,P,B幀)、片組、片(包括I,P,B片,SP片,SI片)、NALU、巨集塊、亞巨集塊、塊、畫素

注:影象以序列為單位進行組織

-------------------------------------------------------------------------------------------------------------

幀、NALU、片

(1)、在 H.264協議中影象是個集合概念,頂場、底場、幀都可以稱為影象(本文影象概念時都是集合概念)。因此我們可以知道,對於H.264 協議來說,我們平常所熟悉的那些稱呼,例如:I 幀、P 幀、B幀等等,實際上都是我們把影象這個概念具體化和細小化了。我們在 H.264裡提到的“幀”通常就是指不分場的影象;
(2)、如果不採用FMO(靈活巨集塊排序) 機制,則一幅影象只有一個片組
(3)、如果不使用多個片,則一個片組只有一個片
(4)、如果不採用DP(資料分割)機制,則一個片就是一個NALU一個 NALU 也就是一個片

      否則,一個片由 三個 NALU 組成(即標準“表7-1”中 nal_unit_type 值為2、3、4 的三個 NALU 屬於 一個片);      2編碼條帶資料分割塊A  slice_data_partition_a_layer_rbsp()

   3 編碼條帶資料分割塊Bslice_data_partition_b_layer_rbsp( )

   4 編碼條帶資料分割塊Cslice_data_partition_c_layer_rbsp( )
也即對應上面的:       
        H264NT_SLICE_DPA,
        H264NT_SLICE_DPB,
        H264NT_SLICE_DPC,

幀可以包含一個或多個片,片由巨集塊組成,巨集塊是編碼處理的基本單元。

一幅影象由 1~N個片組組成,而每一個片組又由一個或若干個片組成一個片由一個NALU或三個NALU(假如有資料分割)組成。影象解碼過程中總是按照片進行解碼,然後按照片組將解碼巨集塊重組成影象。從這種意義上講,片實際是最大的解碼單元
-------------------------------------------------------------------------------------------------------------

I,P,B幀的依賴關係

I frame 是自己獨立編碼,不依賴於其他frame 資料。

P frame 依賴 I frame 資料。

B frame 依賴 I frame, P frame 或其他 B frame 資料。

對應地,NAL nal_unit_type中的1(非IDR影象的編碼條帶)、2(編碼條帶資料分割塊A)、3(編碼條帶資料分割塊B)、4(編碼條帶資料分割塊C)、5(IDR影象的編碼條帶)種類型 與 Slice種的三種編碼模式:I_slice、P_slice、B_slice NAL nal_unit_type 裡的五種型別,代表接下來資料是表示啥資訊的和具體如何分塊。
I_slice、P_slice、B_slice 表示I型別的片、P型別的片,B型別的片.其中I_slice為幀內預測模式編碼;P_slice為單向預測編碼或幀內模式;B_slice 中為雙向預測或幀內模式。

// H.264 NAL type
   enum H264NALTYPE
    {
        H264NT_NAL = 0,
        H264NT_SLICE, //P 幀
        H264NT_SLICE_DPA,
        H264NT_SLICE_DPB,
        H264NT_SLICE_DPC,
        H264NT_SLICE_IDR, // I 幀
        H264NT_SEI,
        H264NT_SPS,
        H264NT_PPS,
   };

//  0x00 0x00  0x00 0x01  0x65(0x45)   前四個位元組為幀頭,0x65  是關鍵幀

//0x00  0x00 0x01  0x65(0x45)  也為關鍵幀


H264GetNALType(unsigned char * pBSBuf, const int nBSLen)
{
if ( nBSLen < 5 )  // 不完整的NAL單元
   return H264NT_NAL;


unsigned char * pBS = (unsigned char *)pBSBuf;

int nType = pBS[4] & 0x1F;  // NAL型別在固定的位置上 
if ( nType <= H264NT_PPS )
    return nType;// nTYPE  為5  表示關鍵幀


return 0;
}

-------------------------------------------------------------------------------------------------------------

NAL語法語義

NAL層句法:

在編碼器輸出的碼流中,資料的基本單元是句法元素。

句法表徵句法元素的組織結構。

語義闡述句法元素的具體含義。

分組都有頭部,解碼器可以很方便的檢測出NAL的分界,依次取出NAL進行解碼。

但為了節省碼流,H.264沒有另外在NAL的頭部設立表示起始位置的句法元素。

如果編碼資料是儲存在介質上的,由於NAL是依次緊密相連的,解碼器就無法在資料流中分辨出每個NAL的起始位置和終止位置。

解決方案:在每個NAL前新增起始碼:0X000001

在某些型別的介質上,為了定址的方便,要求資料流在長度上對齊,或某個常數的整數倍。所以在起始碼前新增若干位元組的0來填充。

檢測NAL的開始:

0X000001和0X000000

我們必須考慮當NAL內部出現了0X000001和0X000000

解決方案:

H.264提出了“防止競爭”機制:

0X000000——0X00000300

0X000001——0X00000301

0X000002——0X00000302

0X000003——0X00000303

為此,我們可以知道:

在NAL單元中,下面的三位元組序列不應在任何位元組對齊的位置出現

0X000000

0X000001

0X000002

Forbidden_zero_bit =0;

Nal_ref_idc:表示NAL的優先順序。0~3,取值越大,表示當前NAL越重要,需要優先受到保護。如果當前NAL是屬於參考幀的片,或是序列引數集,或是影象引數集這些重要的單位時,本句法元素必需大於0。

Nal_unit_type:當前NAL 單元的型別