关于指数哥伦布编码资料:
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;
}