有無符號指數哥倫布編碼 以及解析SPS

關於指數哥倫布編碼資料:

Golomb及指數哥倫布編碼原理介紹及實現

0階無符號指數哥倫布編碼

感謝大佬們的資料!

h264官方協議文檔中定義了4類指數哥倫布編碼分爲:

    ue(v)無符號指數哥倫布編碼 、se(v)有符號指數哥倫布編碼、 te(v)截斷指數哥倫布編碼 和 me(v)映射指數哥倫布編碼

工程相關,這裏僅實現了  ue(v) 、se(v),剩下留待以後有時間慢慢整理。

關於哥倫布編碼一波註釋:

計算得到組號m以及組內的偏移量Offset
        m = ⌊log2(num+1)⌋
        Offset = num+1−2^m

有了組號以及組內的偏移量後,其編碼就比較簡單了,具體過程如下:

首先使用公式計算組號 m,  m=⌊log2(num+1)⌋

對組號m進行編碼,連續寫入m個0,最後寫入一個1作爲結束。
計算組內偏移量offset,    Offset=num+1−2^m

取offset二進制形式的低 m 位作爲offset碼元

0階Exp-Golomb的編碼後的長度是:2∗m+1,

解碼流程:

讀入bit流,是0則繼續,1則停止,然後統計0的個數m;

接着讀入 m 位的bit,就是offset,

最後解碼後的數值是:N=2^m−1+offset

關於SPS各個字段含義:

參照:H264碼流中SPS PPS詳解

這裏僅解析了SPS中的圖像長、寬 以及 FPS,用於視頻文件的封裝。

直接上代碼:

#include <stdio.h>
#include <memory.h>
#include <iostream>
#include <bitset>

typedef unsigned char UINT8;


//返回當前字節 當前位 的值
static int get_bit_at_position(UINT8*buf,UINT8 &bytePosition,UINT8 &bitPosition)
{
	 UINT8 mask = 0,val = 0;
	 mask = 1<<(7-bitPosition) ;	//由高往低
	 val = (buf[bytePosition]&mask)?1:0;
	 if(++bitPosition >7)
	 {
	   bytePosition++;
	   bitPosition = 0;
	 }
	 return val;
}

//獲取 從左往右 n個bit組成的值
static int get_u_code_num(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition,UINT8 bitCount)
{
	 UINT8  bitVal = 0;
	 int  code_num = 0;
	 for (int bit_pos = bitCount-1; bit_pos >-1; bit_pos--)
	 {
	 	  bitVal = get_bit_at_position(buf, bytePosition, bitPosition);
	 	  code_num += (1 << bit_pos)*bitVal;
	 } 
	 return code_num; 
}
//ue(v)無符號指數哥倫布編碼
static int get_uev_code_num(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
{
	if(bitPosition > 0x08)
	 return 0;
	UINT8 bitVal = 0;
	int codeNum = 0,prefix = 0, surfix = 0,leadingZeroBits = 0;
	
	//獲取前導0的個數
	while(true)
	{
	    bitVal = get_bit_at_position(buf, bytePosition, bitPosition);
		if (0 == bitVal)
		{
		   leadingZeroBits++; //前導 0 的統計
		}
		else
		{
		   break;
		}
	}

  /*如 0 0 0     1     0 1 1 
    前綴prefix 爲  2^(leadingZeroBits = 3) -1 = 7
    後綴surfix  0 1 1  = 0*2^2 + 1*2^1 +1*2^0 = 3
	codeNum = prefix + surfix = 10
   */
     prefix = (1 << leadingZeroBits) - 1;

	 for (int bit_pos = leadingZeroBits-1; bit_pos >-1; bit_pos--)
	 {
	 	  bitVal = get_bit_at_position(buf, bytePosition, bitPosition);
	 	  surfix += (1 << bit_pos)*bitVal;
	 }
	
	 codeNum = prefix + surfix;
	 return codeNum;
}
//ceil向上取整 floor//向下取整
//se(v) 是由 我們上面計算的codeNum通過公式 (−1)codeNum+1 Ceil(codeNum÷2 )  變換得來,
static int get_sev_code_num(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
{
	if(bitPosition > 0x08)
	return 0;
	UINT8 bitVal = 0;
	int SeNum = 0,codeNum = 0,prefix = 0, surfix = 0,leadingZeroBits = 0;

	//獲取前導0的個數
	while(true)
	{
	    bitVal = get_bit_at_position(buf, bytePosition, bitPosition);
		if (0 == bitVal)
		{
		   leadingZeroBits++; //前導 0 的統計
		}
		else
		{
		   break;
		}
	}

  /*如 0 0 0     1     0 1 1 
    前綴prefix 爲  2^(leadingZeroBits = 3) -1 = 7
    後綴surfix  0 1 1  = 0*2^2 + 1*2^1 +1*2^0 = 3
	codeNum = prefix + surfix = 10
   */
     prefix = (1 << leadingZeroBits) - 1;

	 for (int bit_pos = leadingZeroBits-1; bit_pos >-1; bit_pos--)
	 {
	 	  bitVal = get_bit_at_position(buf, bytePosition, bitPosition);
	 	  surfix += (1 << bit_pos)*bitVal;
	 }
	 codeNum = prefix + surfix;

	 //計算Se 公式 (−1)codeNum+1 Ceil(codeNum÷2 )
	 SeNum = ceil(codeNum/2.0);
	 if((codeNum+1)%2) //奇
		return -SeNum;
	 return SeNum;

}

int main()
{
       //一段HK視頻流的sps
	UINT8 strArray[23]={0x67,0x4d, 0x00, 0x1f, 0x96, 0x35, 0x40, 0xa0, 0x0b, 0x74, 0xdc,
	0x04, 0x04, 0x05, 0x00, 0x00, 0x07, 0x08, 0x00, 0x01, 0x5f, 0x90, 0x04};
	UINT8 bytePosition = 0, bitPosition = 0;

	UINT8 dataBitLength = sizeof(strArray) * 8; //數組的總bit
	//NALU 頭
	int forbidden_bit = get_u_code_num(strArray,bytePosition,bitPosition,1);
	int nal_ref_idc = get_u_code_num(strArray,bytePosition,bitPosition,2);
    int nal_unit_type = get_u_code_num(strArray,bytePosition,bitPosition,5);

	//這裏可能包含防競爭碼 需做處理海康視頻流中並未見此字段

	//sps信息	 
	int profile_idc = get_u_code_num(strArray,bytePosition,bitPosition,8);
    int constraint_set0_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
    int constraint_set1_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
    int constraint_set2_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
    int constraint_set3_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
	int constraint_set4_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
    int constraint_set5_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
	int reserve_zero_2bit = get_u_code_num(strArray,bytePosition,bitPosition,2);

	int level_idc = get_u_code_num(strArray,bytePosition,bitPosition,8);

	int seq_parameter_set_id = get_uev_code_num(strArray,bytePosition,bitPosition);
    int chroma_format_idc = 0;
    if (profile_idc == 100 || profile_idc == 110 ||profile_idc == 122 || profile_idc == 244 ||
		profile_idc == 44 || profile_idc == 83 ||profile_idc == 86 || profile_idc == 118 ||profile_idc == 128||
		profile_idc == 138 || profile_idc == 139 || profile_idc == 134 || profile_idc == 135)
	{
		 chroma_format_idc = get_uev_code_num(strArray,bytePosition,bitPosition);
		 if(chroma_format_idc == 3)
		 {
		 	int separte_colour_plane_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		 }
		 int bit_depth_luma_minus8 = get_uev_code_num(strArray,bytePosition,bitPosition);
		 int bit_depth_chroma_minus8 = get_uev_code_num(strArray,bytePosition,bitPosition);
		 int qpprime_y_zero_transfrom_bypass_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		 int seq_scaling_matrix_preasent_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		 if(seq_scaling_matrix_preasent_flag)
		 {	 
			 int seq_scaling_list_present_flag[12] = {0};
			 for(int i = 0;i<((chroma_format_idc!=3)?8:12);i++)
			 {
			 	seq_scaling_list_present_flag[i] = get_u_code_num(strArray,bytePosition,bitPosition,1);
				//餘下不解析
			 }
		
		 }
	}
 	int log2_max_frame_num_minus4 =  get_uev_code_num(strArray,bytePosition,bitPosition);
	int pic_order_cnt_type =  get_uev_code_num(strArray,bytePosition,bitPosition);
	if(pic_order_cnt_type == 0)
	{
	   int log2_max_pic_order_cnt_lsb_minus4 =  get_uev_code_num(strArray,bytePosition,bitPosition);
	}
	else if(pic_order_cnt_type == 1)
	{
	   int delta_pic_order_always_zero_flag =  get_u_code_num(strArray,bytePosition,bitPosition,1);
	   int offset_for_non_ref_pic = get_sev_code_num(strArray,bytePosition,bitPosition);
	   int offset_for_top_to_bottom_field = get_sev_code_num(strArray,bytePosition,bitPosition);
	   int num_ref_frames_in_pic_order_cnt_cycle = get_uev_code_num(strArray,bytePosition,bitPosition);
	   int* offset_for_ref_frame = new int[num_ref_frames_in_pic_order_cnt_cycle];
	   for(int i = 0;i<num_ref_frames_in_pic_order_cnt_cycle;i++)
	   {
	   	   offset_for_ref_frame[i] = get_sev_code_num(strArray,bytePosition,bitPosition);
	   }
	   delete []offset_for_ref_frame;
	}
	int max_num_ref_frames = get_uev_code_num(strArray,bytePosition,bitPosition);
	int gaps_in_frame_num_value_allowed_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
	
	//視頻寬高
	int pic_width_in_mbs_minusl = get_uev_code_num(strArray,bytePosition,bitPosition);
	int pic_height_in_map_units_minusl = get_uev_code_num(strArray,bytePosition,bitPosition);
	int frame_mbs_only_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
	if(!frame_mbs_only_flag)
	{
		int mb_adaptive_frame_field_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
	}
	int direct_8x8_inference_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
	int frame_cropping_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);

	int frame_crop_left_offset  = 0;
	int frame_crop_right_offset = 0;
	int frame_crop_top_offset = 0;
	int frame_crop_bottom_offset = 0;
	//視頻需要裁剪
	if(frame_cropping_flag)
	{
		 frame_crop_left_offset =  get_uev_code_num(strArray,bytePosition,bitPosition);
		 frame_crop_right_offset =  get_uev_code_num(strArray,bytePosition,bitPosition);
		 frame_crop_top_offset =  get_uev_code_num(strArray,bytePosition,bitPosition);
		 frame_crop_bottom_offset =  get_uev_code_num(strArray,bytePosition,bitPosition);
	}
    int vui_parameter_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1); 
	if(vui_parameter_present_flag)
	{
	   //fps相關不解析
		int aspect_ratio_info_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		if (aspect_ratio_info_present_flag)
		{
			int aspect_ratio_idc = get_u_code_num(strArray,bytePosition,bitPosition,8);
			if (aspect_ratio_idc == 255) 
			{      //Extended_SAR
				int sar_width = get_u_code_num(strArray,bytePosition,bitPosition,16);      //sar_width
				int sar_height = get_u_code_num(strArray,bytePosition,bitPosition,16);      //sar_height
			}
		}
		int overscan_info_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		if (overscan_info_present_flag) 
		{
			int overscan_appropriate_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);    
		}
		int video_signal_type_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		if (video_signal_type_present_flag) 
		{
			int video_format = get_u_code_num(strArray,bytePosition,bitPosition,3);
			int video_full_range_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
			int colour_description_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
			if (colour_description_present_flag) 
			{
				int colour_primaries = get_u_code_num(strArray,bytePosition,bitPosition,8);
				int transfer_characteristics = get_u_code_num(strArray,bytePosition,bitPosition,8);
				int matrix_coefficients = get_u_code_num(strArray,bytePosition,bitPosition,8);
			}
		}
		  
		int chroma_loc_info_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		if (chroma_loc_info_present_flag) 
		{
			int chroma_sample_loc_type_top_field = get_uev_code_num(strArray,bytePosition,bitPosition);    
			int chroma_sample_loc_type_bottom_field = get_uev_code_num(strArray,bytePosition,bitPosition);    
		}

		int timing_info_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		if (timing_info_present_flag) 
		{
			int num_units_in_tick = get_u_code_num(strArray,bytePosition,bitPosition,32);
			int time_scale = get_u_code_num(strArray,bytePosition,bitPosition,32);
			int fixed_frame_rate_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);

			//在H.264標準中,比率'num_units_in_tic / time_scale'的概念
			//取決於nuit_field_based_flag。
			//如果nuit_field_based_flag = 1,則上述比率表示場速率,否則它表示幀速率。
			//顯然在x.264中nuit_field_based_flag被設置爲1,因此比率num_units_in_tic / time_scale被進一步除以2以獲得幀速率。

			int fps = (int)((float)time_scale / (float)num_units_in_tick);
			if (fixed_frame_rate_flag) 
			{
				fps = fps/2;
			}
		}

		int nal_hrd_parameters_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);;
		if (nal_hrd_parameters_present_flag) 
		{
			//hrd_parameters()  //see E.1.2 HRD parameters syntax
		}

		//後面代碼需要hrd_parameters()函數接口實現纔有用
		int vcl_hrd_parameters_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		if (vcl_hrd_parameters_present_flag) 
		{
			//hrd_parameters()
		}
		if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) 
		{
			int low_delay_hrd_flag = get_u_code_num(strArray,bytePosition,bitPosition,1); 
		}

	    int pic_struct_present_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		int bitstream_restriction_flag = get_u_code_num(strArray,bytePosition,bitPosition,1);
		if (bitstream_restriction_flag) 
		{
			int motion_vectors_over_pic_boundaries_flag  = get_u_code_num(strArray,bytePosition,bitPosition,1);
			int max_bytes_per_pic_denom = get_uev_code_num(strArray,bytePosition,bitPosition);
			int max_bits_per_mb_denom = get_uev_code_num(strArray,bytePosition,bitPosition);
			int log2_max_mv_length_horizontal = get_uev_code_num(strArray,bytePosition,bitPosition);
			int log2_max_mv_length_vertical = get_uev_code_num(strArray,bytePosition,bitPosition);
			int max_num_reorder_frames = get_uev_code_num(strArray,bytePosition,bitPosition);
			int max_dec_frame_buffering = get_uev_code_num(strArray,bytePosition,bitPosition);
		}
	}


	int  width = ((int)pic_width_in_mbs_minusl + 1) * 16;
    int  height = (2 - (int)frame_mbs_only_flag) * ((int)pic_height_in_map_units_minusl + 1) * 16;

	if (1 == frame_cropping_flag)
	{
		int crop_unit_x;
		int crop_unit_y;
		if (0 == chroma_format_idc) // monochrome
		{
			crop_unit_x = 1;
			crop_unit_y = 2 - frame_mbs_only_flag;
		}
		else if (1 == chroma_format_idc) // 4:2:0
		{
			crop_unit_x = 2;
			crop_unit_y = 2 * (2 - frame_mbs_only_flag);
		}
		else if (2 == chroma_format_idc) // 4:2:2
		{
			crop_unit_x = 2;
			crop_unit_y = 2 - frame_mbs_only_flag;
		}
		else // 3 == sps.chroma_format_idc // 4:4:4
		{
			crop_unit_x = 1;
			crop_unit_y = 2 - frame_mbs_only_flag;
		}

		width -= crop_unit_x * ((int)frame_crop_left_offset + (int)frame_crop_right_offset);
		height -= crop_unit_y * ((int)frame_crop_top_offset + (int)frame_crop_bottom_offset);

	}
	
	printf("Width: %d \n",width);
	printf("height: %d \n",height);

	getchar();
	return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章