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解析分辨率

H264之sps解析分辨率相关推荐

  1. 音视频系列--哥伦布编码和H264片段sps解析宽高信息

    H.264码流中的NALU进行了一个简单的划分,标出了NALU的类型和长度等信息.因为我们在解析SPS和PPS中要使用到指数哥伦布编码的解析,所以有必要了解一下指数哥伦布编码. 一.指数哥伦布编码(理 ...

  2. 解析H264的SPS信息

    原文链接 在做音视频开发的时候,存在不解码视频帧的前提下需要获取视频宽高.帧率等信息,而H.264中的SPS数据可为我们提供这些相关的信息.在此之前,我们需要对一些协议和算法有一定的初步了解,后文中有 ...

  3. H264参数SPS(序列参数集)和PPS(图像参数集)说明

    H264参数SPS(序列参数集)和PPS(图像参数集)说明 https://blog.csdn.net/heanyu/article/details/6191576 https://blog.csdn ...

  4. MP4文件中h264的 SPS、PPS获取

    SkySeraph 博客园 首页 博问 闪存 新随笔 联系 订阅 管理 随笔- 190 文章- 0 评论- 407  [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 ...

  5. H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流

    SkySeraph Apr 1st 2012 Email:skyseraph00@163.com 一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装 ...

  6. 【流媒体】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流

    一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装格式核心概念 MP4封装格式对应标准为 ISO/IEC 14496-12(信息技术 视听对象编码的 ...

  7. MP4格式及在MP4文件中提取H264的SPS、PPS及码流

    一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装格式核心概念 1  MP4封装格式对应标准为 ISO/IEC 14496-12(信息技术 视听对象 ...

  8. 【流媒體】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流

    原文地址为: [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 SkySeraph A ...

  9. [转]【流媒體】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流

    [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 SkySeraph Apr 1st 2012  Email:skyseraph00@163 .com 一.MP4格式基 ...

最新文章

  1. matlab奈馈斯图,matlab关于控制的设计单位负反馈的校正
  2. rtmp 封包及消息
  3. 共享文件服务器迁移,服务器共享文件夹迁移
  4. ubuntu10.04 android编译问题
  5. 完成MSP430的IAP升级程序(总结)
  6. python安装找不到硬盘_python2.7下安装theano
  7. 3d文件与html结合,js和HTML5怎么结合?
  8. 95-235-040-源码-task-Flink 对用户代码异常处理
  9. 2.精通前端系列技术之JS模块化开发-深入学习seaJs(四)
  10. R语言入门1:安装R和RStudio
  11. R语言: 如何快速获取一个地方的气象数据?
  12. 04_部署 etcd 集群
  13. IELTS12 Test6 the population of some countries include a relatively large number of young adults
  14. ArcGIS Pro 创建tpk
  15. linux mint 环境配置jimi
  16. 文件夹访问被拒绝,您需要权限来执行操作
  17. 华邦存储芯片 W25Q 系列命名规则
  18. stata质别变量赋值_【STATA学习笔记】虚拟变量的生成
  19. 用python动手学统计学_3-5样本统计量的性质
  20. DSSS、OFDM、FHSS的区别与联系

热门文章

  1. 迷你MVVM框架 avalonjs 0.71发布
  2. int main():声明指定了两个以上的数据类型
  3. ViT (Vision Transformer) ----LSTM网络
  4. 对象删除某个属性_JS对象基本用法
  5. 树莓派能直接运行python程序_在树莓派上运行python脚本 - python
  6. php 进行http请求,php模拟http请求的两种方式
  7. java鼠标事件_Java 模拟鼠标事件
  8. P2424 约数和 真丶除法分块
  9. CF995A Tesla
  10. 阿里移动推送服务端API