H264之sps解析分辨率

sps定义如下:

解析如下:

分辨率:

宽高可从SPS字段计算得到,公式如下:

Width = (pic_width_in_mbs_minus1+1)*16;
Height = (pic_height_in_map_units_minus1+1)*16;

但以上是针对宽高是16的整数倍的情况,当不是16整数倍
时,frame_cropping_flag值为1,frame_mbs_only_flag为1,公式如下:
(也可以认为统一使用下面的公式)

width = ((pic_width_in_mbs_minus1 +1)*16) - frame_crop_left_offset*2 - frame_crop_right_offset*2;

height= ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16) - (frame_crop_top_offset * 2) - (frame_crop_bottom_offset * 2);

以上公式是一年多以前在网上找的,仔细看手册,上面的公式有局限性。根据H264
手册Table6-1及7.4.2.1.1,参考mkvtoolnix代码,比如稳妥的计算方法如下:

    // 宽高计算公式
    width  = (sps->pic_width_in_mbs_minus1+1) * 16;
    height = (2 - sps->frame_mbs_only_flag)* (sps->pic_height_in_map_units_minus1 +1) * 16);
    
    if(sps->frame_cropping_flag)
    {
        unsigned int crop_unit_x;
        unsigned int crop_unit_y;
        if (0 == sps->chroma_format_idc) // monochrome
        {
            crop_unit_x = 1;
            crop_unit_y = 2 - sps->frame_mbs_only_flag;
        }
        else if (1 == sps->chroma_format_idc) // 4:2:0
        {
            crop_unit_x = 2;
            crop_unit_y = 2 * (2 - sps->frame_mbs_only_flag);
        }
        else if (2 == sps->chroma_format_idc) // 4:2:2
        {
            crop_unit_x = 2;
            crop_unit_y = 2 - sps->frame_mbs_only_flag;
        }
        else // 3 == sps.chroma_format_idc   // 4:4:4
        {
            crop_unit_x = 1;
            crop_unit_y = 2 - sps->frame_mbs_only_flag;
        }
        
        width  -= crop_unit_x * (sps->frame_crop_left_offset + sps->frame_crop_right_offset);
        height -= crop_unit_y * (sps->frame_crop_top_offset  + sps->frame_crop_bottom_offset);
    }


*****************-----------------哥伦布编码-----------**************************

上面的有3种数据结构:u(1),ue(v),se(v), (转自https://blog.csdn.net/u012188065/article/details/53590641)

下面分别介绍:

u(1) :为一个字节取出前1位

ue(v) 为无符号指数哥伦布熵编码

编码过程如下:

对 4 进行无符号指数哥伦布熵编码
1、将4加1(为5)转换为最小的二进制序列即 101 (此是M=3)
2、此二进制序列前面补充M-1即两个0

3、得出的4的无符号指数哥伦布熵编码的序列为 00101

解码过程如下:

如对 00101进行无符号指数哥伦布熵解码
1、获取开头连续的N个0, 此时N = 2
2、再向后读取N+1位的值,即 101,为5

3、 5 - 1 =4 获取其解码后码值

se(v) 为有符号指数哥伦布熵编码

编码过程如下:

如对4进行有符号指数哥伦布熵编码
1、4的绝对值转为最小二进制序列,即 100 (此时M = 3)
2、后面补充符号位,0 即 1000

3、前面补充M个0, 即 0001000

解码过程如下:

如对二进制序列 0001000 进行有符号指数哥伦布熵解码
1、获取开头连续的N个0, 此时N = 3
2、再获取N为数值,即 100 即为4
3、获取最后的符号位,0,即为正值

4、故此序列解码后的码值为4


示例二:

编码

如对-15进行有符号指数哥伦布熵编码
1、-7的绝对值转为最小二进制序列,即 1111 (此时M = 4)
2、后面补充符号位,1,即 11111

3、前面补充M个0,即 000011111

解码:

如对二进制序列 000011111 进行有符号指数哥伦布熵解码
1、获取开头连续的N个0, 此时N = 4
2、再获取N为数值,即 1111 即为15
3、获取最后的符号位,1,即为负值
4、故此序列解码后的码值为-15

****************************代码实现*****************************************

U(n)数据类型的实现

static int U(int iBitCount, byte[] bData, ref int iStartBit)
        {
            int iRet = 0;
            for(int i =0;i<iBitCount;i++)
            {
                iRet = iRet << 1;
                if ((0x80 >> (iStartBit % 8)) == (bData[iStartBit / 8] & (0x80 >> (iStartBit % 8))))
                {
                    iRet += 1;
                }
                iStartBit++;
            }
            return iRet;
        }

Ue数据类型的解析

static UInt32 Ue(byte[] bData, ref int iStartBit)
        {
            //计算0bit的个数
            int nZeroNum = 0;
            while (iStartBit < bData.Length * 8)
            {
                if ((0x80 >> (iStartBit % 8)) == (bData[iStartBit / 8] & (0x80 >> (iStartBit % 8)))) //&:按位与,%取余
                {
                    break;
                }
                nZeroNum++;
                iStartBit++;
            }
            nZeroNum = nZeroNum + 1;
            //计算结果
            UInt32 dwRet = 0;
            for (UInt32 i = 0; i < nZeroNum; i++)
            {
                dwRet <<= 1;
                if ((0x80 >> (iStartBit % 8)) == (bData[iStartBit / 8] & (0x80 >> (iStartBit % 8))))
                {
                    dwRet += 1;
                }
                iStartBit++;
            }
            return dwRet-1;
        }

Se数据类型的解析

static Int32 Se(byte[] bData, ref int iStartBit)
        {
            //计算0bit的个数
            int nZeroNum = 0;
            while (iStartBit < bData.Length * 8)
            {
                if ((0x80 >> (iStartBit % 8)) == (bData[iStartBit / 8] & (0x80 >> (iStartBit % 8)))) //&:按位与,%取余
                {
                    break;
                }
                nZeroNum++;
                iStartBit++;
            }
            //计算结果
            Int32 dwRet = 0;
            for (UInt32 i = 0; i < nZeroNum; i++)
            {
                dwRet <<= 1;
                if ((0x80 >> (iStartBit % 8)) == (bData[iStartBit / 8] & (0x80 >> (iStartBit % 8))))
                {
                    dwRet += 1;
                }
                iStartBit++;
            }
            if ((0x80 >> (iStartBit % 8)) == (bData[iStartBit / 8] & (0x80 >> (iStartBit % 8))))
            {
                dwRet = 0-dwRet;
            }
            iStartBit++;
            return dwRet;
        }

sps解析出长和宽如下:

public static bool H264_decode_sps(byte[] bData, ref int width, ref int height)
        {
            int StartBit = 0;
            int forbidden_zero_bit = U(1, bData, ref StartBit);
            int nal_ref_idc = U(2, bData, ref StartBit);
            int nal_unit_type = U(5, bData, ref StartBit);
            if (nal_unit_type == 7)
            {
                int profile_idc = U(8, bData, ref StartBit);
                int constraint_set0_flag = U(1, bData, ref StartBit);//(buf[1] & 0x80)>>7;
                int constraint_set1_flag = U(1, bData, ref StartBit);//(buf[1] & 0x40)>>6;
                int constraint_set2_flag = U(1, bData, ref StartBit);//(buf[1] & 0x20)>>5;
                int constraint_set3_flag = U(1, bData, ref StartBit);//(buf[1] & 0x10)>>4;
                int reserved_zero_4bits = U(4, bData, ref StartBit);
                int level_idc = U(8, bData, ref StartBit);
                UInt32 seq_parameter_set_id = Ue(bData, ref StartBit);
                UInt32 chroma_format_idc = 0;
                if (profile_idc == 100 || profile_idc == 110 ||
                    profile_idc == 122 || profile_idc == 144)
                {
                    chroma_format_idc = Ue(bData, ref StartBit);
                    if (chroma_format_idc == 3)
                    {
                        int residual_colour_transform_flag = U(1, bData, ref StartBit);
                    }
                    UInt32 bit_depth_luma_minus8 = Ue(bData, ref StartBit);
                    UInt32 bit_depth_chroma_minus8 = Ue(bData, ref StartBit);
                    int qpprime_y_zero_transform_bypass_flag = U(1, bData, ref StartBit);
                    int seq_scaling_matrix_present_flag = U(1, bData, ref StartBit);

                    int[] seq_scaling_list_present_flag = new int[8];
                    if (1 == seq_scaling_matrix_present_flag)
                    {
                        for (int i = 0; i < 8; i++)
                        {
                            seq_scaling_list_present_flag[i] = U(1, bData, ref StartBit);
                        }
                    }
                }
                UInt32 log2_max_frame_num_minus4 = Ue(bData, ref StartBit);
                UInt32 pic_order_cnt_type = Ue(bData, ref StartBit);
                if (pic_order_cnt_type == 0)
                {
                    UInt32 log2_max_pic_order_cnt_lsb_minus4 = Ue(bData, ref StartBit);
                }
                else if (pic_order_cnt_type == 1)
                {
                    int delta_pic_order_always_zero_flag = U(1, bData, ref StartBit);
                    int offset_for_non_ref_pic = Se(bData, ref StartBit);
                    int offset_for_top_to_bottom_field = Se(bData, ref StartBit);
                    UInt32 num_ref_frames_in_pic_order_cnt_cycle = Ue(bData, ref StartBit);

                    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] = Se(bData, ref StartBit);
                }
                UInt32 num_ref_frames = Ue(bData, ref StartBit);
                int gaps_in_frame_num_value_allowed_flag = U(1, bData, ref StartBit);
                UInt32 pic_width_in_mbs_minus1 = Ue(bData, ref StartBit);
                UInt32 pic_height_in_map_units_minus1 = Ue(bData, ref StartBit);


                int frame_mbs_only_flag = U(1, bData, ref StartBit);
                if (0 == frame_mbs_only_flag)
                {
                    int mb_adaptive_frame_field_flag = U(1, bData, ref StartBit);
                }
                int direct_8x8_inference_flag = U(1, bData, ref StartBit);
                int frame_cropping_flag = U(1, bData, ref StartBit);

                UInt32 frame_crop_left_offset = 0;
                UInt32 frame_crop_right_offset = 0;
                UInt32 frame_crop_top_offset = 0;
                UInt32 frame_crop_bottom_offset = 0;

                if (1 == frame_cropping_flag)
                {
                     frame_crop_left_offset = Ue(bData, ref StartBit);
                     frame_crop_right_offset = Ue(bData, ref StartBit);
                     frame_crop_top_offset = Ue(bData, ref StartBit);
                     frame_crop_bottom_offset = Ue(bData, ref StartBit);
                }
                int vui_parameter_present_flag = U(1, bData, ref StartBit);
                if (1 == vui_parameter_present_flag)
                {
                    int aspect_ratio_info_present_flag = U(1, bData, ref StartBit);
                    if (1 == aspect_ratio_info_present_flag)
                    {
                        int aspect_ratio_idc = U(8, bData, ref StartBit);
                        if (aspect_ratio_idc == 255)
                        {
                            int sar_width = U(16, bData, ref StartBit);
                            int sar_height = U(16, bData, ref StartBit);
                        }
                    }
                    int overscan_info_present_flag = U(1, bData, ref StartBit);
                    if (1 == overscan_info_present_flag)
                    {
                        int overscan_appropriate_flagu = U(1, bData, ref StartBit);
                    }
                    int video_signal_type_present_flag = U(1, bData, ref StartBit);
                    if (1 == video_signal_type_present_flag)
                    {
                        int video_format = U(3, bData, ref StartBit);
                        int video_full_range_flag = U(1, bData, ref StartBit);
                        int colour_description_present_flag = U(1, bData, ref StartBit);
                        if (1 == colour_description_present_flag)
                        {
                            int colour_primaries = U(8, bData, ref StartBit);
                            int transfer_characteristics = U(8, bData, ref StartBit);
                            int matrix_coefficients = U(8, bData, ref StartBit);
                        }
                    }
                    int chroma_loc_info_present_flag = U(1, bData, ref StartBit);
                    if (1 == chroma_loc_info_present_flag)
                    {
                        UInt32 chroma_sample_loc_type_top_field = Ue(bData, ref StartBit);
                        UInt32 chroma_sample_loc_type_bottom_field = Ue(bData, ref StartBit);
                    }
                    int timing_info_present_flag = U(1, bData, ref StartBit);

                    if (1 == timing_info_present_flag)
                    {
                        int num_units_in_tick = U(32, bData, ref StartBit);
                        int time_scale = U(32, bData, ref StartBit);
                        int fixed_frame_rate_flag = U(1, bData, ref StartBit);
                    }

                }

                // 宽高计算公式
                width = ((int)pic_width_in_mbs_minus1 + 1) * 16;
                height = (2 - (int)frame_mbs_only_flag) * ((int)pic_height_in_map_units_minus1 + 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);
                }
                return true;
            }
            else
            {
                return false;
            }

        }

为了便于大家学习和交流,采用vs2017开发 C#语言实现 工程地址如下:

H264之sps解析分辨率


猜你喜欢

转载自blog.csdn.net/g0415shenw/article/details/80733405
今日推荐