關于指數哥倫布編碼資料:
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;
}