1. 程式人生 > >h265 Nalu型別判斷及 sps 資料解析

h265 Nalu型別判斷及 sps 資料解析

  一,Nalu解析                       

 首先來介紹下h265(HEVC)nal單元頭,與h264的nal層相比,h265的nal unit header有兩個位元組構成,如下圖所示 

0                   1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | F | Type | LayerId | TID | +------------ - +---------------- - +  

其語法如下表中的定義:

nal_unit_header( ) {

Descriptor

     forbidden_zero_bit

f(1)

     nal_unit_type

u(6)

     nuh_reserved_zero_6bits

u(6)

     nuh_temporal_id_plus1

u(3)

}

從圖中可以看出hHEVC的nal包結構與h264有明顯的不同,hevc加入了nal所在的時間層的ID,取去除了nal_ref_idc,此資訊合併到了naltype中,

通常情況下F為0,layerid為0,  TID為1。

H265 幀型別判斷:

和264的&0x1f不同。265是 : int type = (code & 0x7E)>>1;

在檔案中查詢00 00 00 01NALU頭,發現在有6種開頭分別為:

再根據H265的NALU型別定義分析,

        00 00 00 01 40 01  的nuh_unit_type的值為 32, 語義為視訊引數集        VPS

       00 00 00 01 42 01  的nuh_unit_type的值為 33, 語義為序列引數集         SPS

       00 00 00 01 44 01  的nuh_unit_type的值為 34, 語義為影象引數集         PPS

       00 00 00 01 4E 01  的nuh_unit_type的值為 39, 語義為補充增強資訊       SEI

       00 00 00 01 26 01  的nuh_unit_type的值為 19, 語義為可能有RADL影象的IDR影象的SS編碼資料   IDR

       00 00 00 01 02 01  的nuh_unit_type的值為1, 語義為被參考的後置影象,且非TSA、非STSA的SS編碼資料

      在編碼過程中,從編碼器獲取碼流的時候,1、2、3、4、5是在一幀資料當中。相當於H264的I幀。

Nalu Type的定義

enum NalUnitType  
{  
  NAL_UNIT_CODED_SLICE_TRAIL_N = 0,   // 0  
  NAL_UNIT_CODED_SLICE_TRAIL_R,   // 1  
    
  NAL_UNIT_CODED_SLICE_TSA_N,     // 2  
  NAL_UNIT_CODED_SLICE_TLA,       // 3   // Current name in the spec: TSA_R  
    
  NAL_UNIT_CODED_SLICE_STSA_N,    // 4  
  NAL_UNIT_CODED_SLICE_STSA_R,    // 5  
  
  NAL_UNIT_CODED_SLICE_RADL_N,    // 6  
  NAL_UNIT_CODED_SLICE_DLP,       // 7 // Current name in the spec: RADL_R  
    
  NAL_UNIT_CODED_SLICE_RASL_N,    // 8  
  NAL_UNIT_CODED_SLICE_TFD,       // 9 // Current name in the spec: RASL_R  
  
  NAL_UNIT_RESERVED_10,  
  NAL_UNIT_RESERVED_11,  
  NAL_UNIT_RESERVED_12,  
  NAL_UNIT_RESERVED_13,  
  NAL_UNIT_RESERVED_14,  
  NAL_UNIT_RESERVED_15, NAL_UNIT_CODED_SLICE_BLA,       // 16   // Current name in the spec: BLA_W_LP  
NAL_UNIT_CODED_SLICE_BLA,       // 16   // Current name in the spec: BLA_W_LP  
  NAL_UNIT_CODED_SLICE_BLANT,     // 17   // Current name in the spec: BLA_W_DLP  
  NAL_UNIT_CODED_SLICE_BLA_N_LP,  // 18  
  NAL_UNIT_CODED_SLICE_IDR,       // 19  // Current name in the spec: IDR_W_DLP  
  NAL_UNIT_CODED_SLICE_IDR_N_LP,  // 20  
  NAL_UNIT_CODED_SLICE_CRA,       // 21  
  NAL_UNIT_RESERVED_22,  
  NAL_UNIT_RESERVED_23,  
  
  NAL_UNIT_RESERVED_24,  
  NAL_UNIT_RESERVED_25,  
  NAL_UNIT_RESERVED_26,  
  NAL_UNIT_RESERVED_27,  
  NAL_UNIT_RESERVED_28,  
  NAL_UNIT_RESERVED_29,  
  NAL_UNIT_RESERVED_30,  
  NAL_UNIT_RESERVED_31,  
  
  NAL_UNIT_VPS,                   // 32  
  NAL_UNIT_SPS,                   // 33  
  NAL_UNIT_PPS,                   // 34  
  NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35  
  NAL_UNIT_EOS,                   // 36  
  NAL_UNIT_EOB,                   // 37  
  NAL_UNIT_FILLER_DATA,           // 38  
  NAL_UNIT_SEI,                   // 39 Prefix SEI  
  NAL_UNIT_SEI_SUFFIX,            // 40 Suffix SEI  
  NAL_UNIT_RESERVED_41,  
  NAL_UNIT_RESERVED_42,  
  NAL_UNIT_RESERVED_43,  
  NAL_UNIT_RESERVED_44,  
  NAL_UNIT_RESERVED_45,  
  NAL_UNIT_RESERVED_46,  
  NAL_UNIT_RESERVED_47,  
  NAL_UNIT_UNSPECIFIED_48,  
  NAL_UNIT_UNSPECIFIED_49,  
  NAL_UNIT_UNSPECIFIED_50,  
  NAL_UNIT_UNSPECIFIED_51,  
  NAL_UNIT_UNSPECIFIED_52,  
  NAL_UNIT_UNSPECIFIED_53,  
  NAL_UNIT_UNSPECIFIED_54,  
  NAL_UNIT_UNSPECIFIED_55,  
  NAL_UNIT_UNSPECIFIED_56,  
  NAL_UNIT_UNSPECIFIED_57,  
  NAL_UNIT_UNSPECIFIED_58,  
  NAL_UNIT_UNSPECIFIED_59,  
  NAL_UNIT_UNSPECIFIED_60,  
  NAL_UNIT_UNSPECIFIED_61,  
  NAL_UNIT_UNSPECIFIED_62,  
  NAL_UNIT_UNSPECIFIED_63,  
  NAL_UNIT_INVALID,  
};  

     二,     SPS解析                                         

1、重新定義型別

typedef unsigned char   uint8;   

typedef unsigned short uint16;

typedef unsigned longuint32;
typedef unsigned __int64uint64;
typedef signed charint8;
typedef signed shortint16;
typedef signed longint32;
typedef signed __int64int64;

2、定義Sps 需要的相關引數

struct vc_params_t
{
	LONG width,height;
	DWORD profile, level;
	DWORD nal_length_size;
	void clear()
	{
		memset(this, 0, sizeof(*this));
	}
};

3、定義網路抽象層Nal類 

 class NALBitstream
 {
 public:
	 NALBitstream() : m_data(NULL), m_len(0), m_idx(0), m_bits(0), m_byte(0), m_zeros(0) 
	 {

	 };
	 NALBitstream(void * data, int len) 
	 {
		 Init(data, len); 
	 };
	 void Init(void * data, int len) 
	 {
		 m_data = (LPBYTE)data;
		 m_len = len;
		 m_idx = 0; 
		 m_bits = 0;
		 m_byte = 0; 
		 m_zeros = 0; 
	 };
	 BYTE GetBYTE()
	 {
		 if ( m_idx >= m_len )
			 return 0;
		 BYTE b = m_data[m_idx++];
		 if ( b == 0 )
		 {
			 m_zeros++;
			 if ( (m_idx < m_len) && (m_zeros == 2) && (m_data[m_idx] == 0x03) )
			 {
				 m_idx++;
				 m_zeros=0;
			 }
		 } 
		 else  m_zeros = 0;

		 return b;
	 };

	 UINT32 GetBit() 
	 {
		 if (m_bits == 0) 
		 {
			 m_byte = GetBYTE();
			 m_bits = 8;
		 }
		 m_bits--;
		 return (m_byte >> m_bits) & 0x1;
	 };

	 UINT32 GetWord(int bits) 
	 {
		 UINT32 u = 0;
		 while ( bits > 0 )
		 {
			 u <<= 1;
			 u |= GetBit();
			 bits--;
		 }
		 return u;
	 };

	 UINT32 GetUE() 
	 {
		 int zeros = 0;
		 while (m_idx < m_len && GetBit() == 0 ) zeros++;
		 return GetWord(zeros) + ((1 << zeros) - 1);
	 };

	 INT32 GetSE()
	 {
		 UINT32 UE = GetUE();
		 bool positive = UE & 1;
		 INT32 SE = (UE + 1) >> 1;
		 if ( !positive )
		 {
			 SE = -SE;
		 }
		 return SE;
	 };
 private:
	 LPBYTE m_data;
	 int m_len;
	 int m_idx;
	 int m_bits;
	 BYTE m_byte;
	 int m_zeros;
 };

 bool  ParseSequenceParameterSet(BYTE* data,int size, vc_params_t& params)
 {
	 if (size < 20)
	 { 
		 return false;
	 }
	 NALBitstream bs(data, size);
	 // seq_parameter_set_rbsp()
	 bs.GetWord(4);// sps_video_parameter_set_id
	 int sps_max_sub_layers_minus1 = bs.GetWord(3); 
	 if (sps_max_sub_layers_minus1 > 6) 
	 {
		 return false;
	 }
	 bs.GetWord(1); 
	 {
		 bs.GetWord(2); 
		 bs.GetWord(1); 
		 params.profile = bs.GetWord(5); 
		 bs.GetWord(32);//
		 bs.GetWord(1);// 
		 bs.GetWord(1);// 
		 bs.GetWord(1);// 
		 bs.GetWord(1);//  
		 bs.GetWord(44);// 
		 params.level   = bs.GetWord(8);// general_level_idc
		 uint8 sub_layer_profile_present_flag[6] = {0};
		 uint8 sub_layer_level_present_flag[6]   = {0};
		 for (int i = 0; i < sps_max_sub_layers_minus1; i++) {
			 sub_layer_profile_present_flag[i]= bs.GetWord(1);
			 sub_layer_level_present_flag[i]= bs.GetWord(1);
		 }
		 if (sps_max_sub_layers_minus1 > 0) 
		 {
			 for (int i = sps_max_sub_layers_minus1; i < 8; i++) {
				 uint8 reserved_zero_2bits = bs.GetWord(2);
			 }
		 }
		 for (int i = 0; i < sps_max_sub_layers_minus1; i++) 
		 {
			 if (sub_layer_profile_present_flag[i]) {
				 bs.GetWord(2); 
				 bs.GetWord(1); 
				 bs.GetWord(5);/ 
					 bs.GetWord(32); 
				 bs.GetWord(1); 
				 bs.GetWord(1); 
				 bs.GetWord(1); 
				 bs.GetWord(1); 
				 bs.GetWord(44); 
			 }
			 if (sub_layer_level_present_flag[i]) {
				 bs.GetWord(8);// sub_layer_level_idc[i]
			 }
		 }
	 }
	 uint32 sps_seq_parameter_set_id= bs.GetUE();  
	 if (sps_seq_parameter_set_id > 15) {
		 return false;
	 }
	 uint32 chroma_format_idc = bs.GetUE();  
	 if (sps_seq_parameter_set_id > 3) {
		 return false;
	 }
	 if (chroma_format_idc == 3) {
		 bs.GetWord(1);//  
	 }
	 params.width  = bs.GetUE(); // pic_width_in_luma_samples
	 params.height  = bs.GetUE(); // pic_height_in_luma_samples
	 if (bs.GetWord(1)) { 
		 bs.GetUE();  
		 bs.GetUE();  
		 bs.GetUE();  
		 bs.GetUE();   
	 }
	 uint32 bit_depth_luma_minus8= bs.GetUE();
	 uint32 bit_depth_chroma_minus8= bs.GetUE();
	 if (bit_depth_luma_minus8 != bit_depth_chroma_minus8) {
		 return false;
	 }
	 //...
	 return true;
 }

4、測試程式碼

int _tmain(int argc, _TCHAR* argv[])

{
	vc_params_t params = { 0 };

	BYTE Sps[41] = { 0X42,0X01,0X01,0X01,0X60,0X00,0X00,0X03,0X00,0X80,0X00,0X00,0X03,0X00,0X00,
		0X03,0X00,0X5D,0XA0,0X02,0X80, 0X80,0X2D,0X16,0X59,0X5E,0X49,0X32,0XB8,0X04,0X00,0X00,0X03,
		0X00,0X04,0X00,0X00,0X03,0X00,0X64,0X20 };

	ParseSequenceParameterSet(Sps, 41, params);

	printf("%d-%d-%d\n", params.width, params.height, params.level);
	system("pause");
	return 0;
}