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解析分辨率
H264之sps解析分辨率相关推荐
- 音视频系列--哥伦布编码和H264片段sps解析宽高信息
H.264码流中的NALU进行了一个简单的划分,标出了NALU的类型和长度等信息.因为我们在解析SPS和PPS中要使用到指数哥伦布编码的解析,所以有必要了解一下指数哥伦布编码. 一.指数哥伦布编码(理 ...
- 解析H264的SPS信息
原文链接 在做音视频开发的时候,存在不解码视频帧的前提下需要获取视频宽高.帧率等信息,而H.264中的SPS数据可为我们提供这些相关的信息.在此之前,我们需要对一些协议和算法有一定的初步了解,后文中有 ...
- H264参数SPS(序列参数集)和PPS(图像参数集)说明
H264参数SPS(序列参数集)和PPS(图像参数集)说明 https://blog.csdn.net/heanyu/article/details/6191576 https://blog.csdn ...
- MP4文件中h264的 SPS、PPS获取
SkySeraph 博客园 首页 博问 闪存 新随笔 联系 订阅 管理 随笔- 190 文章- 0 评论- 407 [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 ...
- H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
SkySeraph Apr 1st 2012 Email:skyseraph00@163.com 一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装 ...
- 【流媒体】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装格式核心概念 MP4封装格式对应标准为 ISO/IEC 14496-12(信息技术 视听对象编码的 ...
- MP4格式及在MP4文件中提取H264的SPS、PPS及码流
一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装格式核心概念 1 MP4封装格式对应标准为 ISO/IEC 14496-12(信息技术 视听对象 ...
- 【流媒體】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
原文地址为: [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 SkySeraph A ...
- [转]【流媒體】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
[流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 SkySeraph Apr 1st 2012 Email:skyseraph00@163 .com 一.MP4格式基 ...
最新文章
- matlab奈馈斯图,matlab关于控制的设计单位负反馈的校正
- rtmp 封包及消息
- 共享文件服务器迁移,服务器共享文件夹迁移
- ubuntu10.04 android编译问题
- 完成MSP430的IAP升级程序(总结)
- python安装找不到硬盘_python2.7下安装theano
- 3d文件与html结合,js和HTML5怎么结合?
- 95-235-040-源码-task-Flink 对用户代码异常处理
- 2.精通前端系列技术之JS模块化开发-深入学习seaJs(四)
- R语言入门1:安装R和RStudio
- R语言: 如何快速获取一个地方的气象数据?
- 04_部署 etcd 集群
- IELTS12 Test6 the population of some countries include a relatively large number of young adults
- ArcGIS Pro 创建tpk
- linux mint 环境配置jimi
- 文件夹访问被拒绝,您需要权限来执行操作
- 华邦存储芯片 W25Q 系列命名规则
- stata质别变量赋值_【STATA学习笔记】虚拟变量的生成
- 用python动手学统计学_3-5样本统计量的性质
- DSSS、OFDM、FHSS的区别与联系
热门文章
- 迷你MVVM框架 avalonjs 0.71发布
- int main():声明指定了两个以上的数据类型
- ViT (Vision Transformer) ----LSTM网络
- 对象删除某个属性_JS对象基本用法
- 树莓派能直接运行python程序_在树莓派上运行python脚本 - python
- php 进行http请求,php模拟http请求的两种方式
- java鼠标事件_Java 模拟鼠标事件
- P2424 约数和 真丶除法分块
- CF995A Tesla
- 阿里移动推送服务端API