一 H.264句法

1.1元素分层结构

H.264编码器输出的Bit流中,每个Bit都隶属于某个句法元素。句法元素被组织成有层次的结构,分别描述各个层次的信息。

图1

H.264分层结构由五层组成,分别是序列参数集、图像参数集、片(Slice)、和宏块和子块。参数集是一个独立的数据单位,不依赖于参数集外的其它句法元素。图2描述了参数集与参数集外的句法元素之间的关系。

图2

一个参数集不对应某一个特定的图像或序列,同一序列参数集可以被多个图像参数集引用,同理,同一个图像参数集也可以被多个图像引用。只在编码器认为需要更新参数集的内容时,才会发出新的参数集。

在H.264中,图像以序列为单位进行组织。一个序列的第一个图像叫做IDR图像,IDR图像都是I帧,H.264引入IDR图像为了解码的同步,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。

IDR是I帧,但I帧不一定是IDR。I帧之后的图像有可能会使用I帧之前的图像做运动参考。

1.2描述子

描述子描述从Bit流中取出句法元素的方法。

编号

语法

说明

1

ae(e)

CABAC

2

b(8)

读进连续的8个Bit

3

ce(v)

CAVLC

4

f(n)

读进连续的n个Bit

5

i(n)/i(v)

读进连续的若干Bit,并把它们解释为有符号整数

6

me(v)

映射指数Golomb熵编码

7

se(v)

有符号指数Golomb熵编码

8

te(v)

截断指数Golomb熵编码

9

u(n)/u(v)

读进连续的若干Bit,并把它们解释为无符号整数

10

ue(v)

无符号指数Golomb熵编码

表1

1.3句法的表示方法

句法元素的名称由小写字母和一系列下划线组成,变量名称是大小写字母组成,中间没有下划线。

二 句法表

定义了H.264的句法,指明在码流中依次出现的句法元素及它们出现的条件、提取描述子等。句法表是分层嵌套的。

句法表中的C字段表示该句法元素的分类,这是为片区服务,分类的具体含义如下表描述。

nal_unit_type

NAL类型

C

0

未使用

1

不分区、非IDR的片

2,3,4

2

片分区A

2

3

片分区B

3

4

版分区C

4

5

IDR图像中的片

2,3

6

补充增强信息单元(SEI)

5

7

序列参数集

0

8

图像参数集

1

9

分界符

6

10

序列结束

7

11

码流结束

8

12

填充

9

13..23

保留

24..31

不保留

表2

2.1 NAL语法

句法

C

Desc

nal_nuit(NumBytesInNALunit){/* NumBytesInNALunit为统计出来的数据长度 */

forbidden_zero_bit /* 等于0 */

All

f(1)

nal_ref_idc/* 当前NAL的优先级,取值范围0-3 */

All

u(2)

nal_unit_type /* NAL类型,见表2描述 */

All

u(5)

NumBytesInRBSP=0

for(i=1;i<NumBytesInNALunit;i++){

if(i+2<NumBytesInNALunit && next_bits(24)==0x000003{

/* 0x000003伪起始码,需要删除0x03这个字节 */

rbsp_byte[NumBytesInRBSP++]

All

b(8)

rbsp_byte[NumBytesInRBSP++]

All

b(8)

i+=2/* 取出前两个0x00后,跳过0x03 */

emulation_prevention_three_byte/* equal to 0x03 */

All

f(8)

}else{

rbsp_byte[NumBytesInRBSP++] /* 继续读取后面的字节 */

All

b(8)

}

}

表3

2.2序列参数集(SPS)

句法

C

Desc

seq_parameter_set_rbsp(){

profile_idc/* 指明所用的Profile */

0

u(8)

constraint_set0_flag

0

u(1)

constraint_set1_flag

0

u(1)

constraint_set1_flag

0

u(1)

reserved_zero_5bits /* equal to 0 */

0

u(5)

level_idc /* 指明所用的Level */

0

u(8)

seq_parameter_set_id /* 指明本序列参数集的id号,0-31,被图像集引用,编码需要产生新的序列集时,使用新的id,而不是改变原来参数集的内容 */

0

ue(v)

log2_max_frame_num_minus4/* 为读取元素frame_num服务,frame_num标识图像的解码顺序,frame_num的解码函数是ue(v),其中v=log2_max_frame_num_minus4+4,该元素同时指明frame_num的最大值MaxFrameNum=2( log2_max_frame_num_minus4+4)*/

0

ue(v)

pic_order_cnt_type /* 指明poc的编码方法,poc标识图像的播放顺序,poc可以由frame_num计算,也可以显示传送。poc共三种计算方式 */

0

ue(v)

if(pic_order_cnt_type==0)

log2_max_pic_order_cnt_lsb_minus4 /* 指明变量MaxPicOrderCntLsb的值, MaxPicOrderCntLsb=2(log2_max_pic_order_cnt_lsb_minus4+4) */

0

ue(v)

else if(pic_order_cnt_type==1){

delta_pic_order_always_zero_flag /* 等于1时,元素delta_pic_order_cnt[0]和delta_pic_order_cnt[1]不在片头中出现,并且它们的默认值是0,等于0时,上述两元素出现的片头中 */

0

u(1)

offset_for_non_ref_pic /* 用来计算非参考帧或场的poc,[-231,231-1] */

0

se(v)

offset_for_top_to_bottom_field/* 计算帧的底场的poc */

0

se(v)

num_ref_frames_inpic_order_cnt_cycle /* 用来解码poc,[0.255] */

0

ue(v)

for(i=0;i<num_ref_frames_inpic_order_cnt_cycle;i++)

offset_for_ref_frame[i]/* 用来解码poc,对于循环中的每个元素指定一个偏移 */

0

se(v)

}

num_ref_frames /* 参考帧队列可达到的最大长度,[0,16] */

0

ue(v)

gaps_in_frame_num_value_allowed_flag /* 为1,允许slice header中的frame_num不连续 */

0

u(1)

pic_width_inmbs_minus1 /* 本元素加1,指明以宏块为单位的图像宽度 PicWidthInMbs=pic_width_in_mbs_minus1+1 */

0

ue(v)

pic_height_in_map_units_minus1 /* 本元素加1,指明以宏块为单位的图像高宽度 PicHeightInMapUnitsMbs=pic_height_in_map_units_minus1+1 */

0

ue(v)

frame_mbs_only_flag /* 等于0表示本序列中所有图像均为帧编码;等于1,表示可能是帧,也可能场或帧场自适应,具体编码方式由其它元素决定。结合前一元素:FrameHeightInMbs=(2-frame_mbs_only_flag)*PicHeightInMapUnits */

0

ue(v)

if(frame_mbs_only_flag)

mb_adaptiv_frame_field_flag /* 指明本序列是否是帧场自适应模式:

frame_mbs_only_flag=1,全部是帧

frame_mbs_only_flag=0, mb_adaptiv_frame_field_flag=0,帧场共存

frame_mbs_only_flag=0, mb_adaptiv_frame_field_flag=1,帧场自适应和场共存*/

0

u(1)

direct_8x8_inference_flag /* 用于指明B片的直接和skip模式下的运动矢量的计算方式 */

0

u(1)

frame_cropping_flag /* 解码器是否要将图像裁剪后输出,如果是,后面为裁剪的左右上下的宽度 */

0

u(1)

if(frame_cropping_flag){

frame_crop_left_offset

0

ue(1)

frame_crop_right_offset

0

ue(1)

frame_crop_top_offset

0

ue(1)

frame_crop_bottom_offset

0

ue(1)

}

vui_parameters_present_flag /* 指明vui子结构是否出现在码流中,vui子结构在附录中指明,用于表征视频格式的信息 */

0

u(1)

if(vui_parameters_present_flag)

vui_parameters()

0

rbsp_trailing_bits()

0

}

表4

//代码//

以下是解析宽高的代码:

view source print ?
001 bool UDPReceiver::getResolution(int channel, int &Width, int& Height)
002 {
003     BYTE *buf = new BYTE[1024];
004     int nLen;
005     AVPacket packet;
006     BOOL bSpsComplete = FALSE;
007     // Find SPS
008     while(!bSpsComplete)
009     {
010         int ret = av_read_frame(m_pFormatContext[channel], &packet);
011         if(packet.flags & AV_PKT_FLAG_KEY)
012         {
013             BYTE* p = packet.data;
014             BYTE last_nal_type = 0;
015             int last_nal_pos = 0;
016             for(int i=0; i<packet.size-5; i++)
017             {
018                 p = packet.data + i;
019                 if(p[0]==0x00&&p[1]==0x00&&p[2]==0x00&&p[3]==0x01)
020                 {
021                     if(last_nal_type == 0x67)
022                     {
023                         nLen = i-last_nal_pos;
024                         memcpy(buf, packet.data+last_nal_pos, nLen);
025                         bSpsComplete = TRUE;
026                     }
027                     last_nal_type = p[4];
028                     last_nal_pos = i;
029                     if(bSpsComplete)
030                     {
031                         break;
032                     }
033                 }
034             }
035             if (last_nal_type == 0x67 && bSpsComplete == FALSE)
036             {
037                 nLen = packet.size - last_nal_pos;
038                 memcpy(buf, packet.data+last_nal_pos, nLen);
039                 bSpsComplete = TRUE;
040             }
041         }
042     }
043     // Analyze SPS to find width and height
044     UINT StartBit=0; 
045         buf = buf + 4;
046     int forbidden_zero_bit=u(1,buf,StartBit);
047     int nal_ref_idc=u(2,buf,StartBit);
048     int nal_unit_type=u(5,buf,StartBit);
049     if(nal_unit_type==7)
050     {
051         int profile_idc=u(8,buf,StartBit);
052         int constraint_set0_flag=u(1,buf,StartBit);//(buf[1] & 0x80)>>7;
053         int constraint_set1_flag=u(1,buf,StartBit);//(buf[1] & 0x40)>>6;
054         int constraint_set2_flag=u(1,buf,StartBit);//(buf[1] & 0x20)>>5;
055         int constraint_set3_flag=u(1,buf,StartBit);//(buf[1] & 0x10)>>4;
056         int reserved_zero_4bits=u(4,buf,StartBit);
057         int level_idc=u(8,buf,StartBit);
058   
059         int seq_parameter_set_id=Ue(buf,nLen,StartBit);
060   
061         if( profile_idc == 100 || profile_idc == 110 ||
062             profile_idc == 122 || profile_idc == 144 )
063         {
064             int chroma_format_idc=Ue(buf,nLen,StartBit);
065             if( chroma_format_idc == 3 )
066                 int residual_colour_transform_flag=u(1,buf,StartBit);
067             int bit_depth_luma_minus8=Ue(buf,nLen,StartBit);
068             int bit_depth_chroma_minus8=Ue(buf,nLen,StartBit);
069             int qpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit);
070             int seq_scaling_matrix_present_flag=u(1,buf,StartBit);
071   
072             int seq_scaling_list_present_flag[8];
073             if( seq_scaling_matrix_present_flag )
074             {
075                 for( int i = 0; i < 8; i++ ) {
076                     seq_scaling_list_present_flag[i]=u(1,buf,StartBit);
077                 }
078             }
079         }
080         int log2_max_frame_num_minus4=Ue(buf,nLen,StartBit);
081         int pic_order_cnt_type=Ue(buf,nLen,StartBit);
082         if( pic_order_cnt_type == 0 )
083             int log2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit);
084         else if( pic_order_cnt_type == 1 )
085         {
086             int delta_pic_order_always_zero_flag=u(1,buf,StartBit);
087             int offset_for_non_ref_pic=Se(buf,nLen,StartBit);
088             int offset_for_top_to_bottom_field=Se(buf,nLen,StartBit);
089             int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit);
090   
091             int *offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];
092             for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
093                 offset_for_ref_frame[i]=Se(buf,nLen,StartBit);
094             delete [] offset_for_ref_frame;
095         }
096         int num_ref_frames=Ue(buf,nLen,StartBit);
097         int gaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit);
098         int pic_width_in_mbs_minus1=Ue(buf,nLen,StartBit);
099         int pic_height_in_map_units_minus1=Ue(buf,nLen,StartBit);
100   
101         Width=(pic_width_in_mbs_minus1+1)*16;
102         Height=(pic_height_in_map_units_minus1+1)*16;
103   
104         return true;
105     }
106     else
107     {
108         return false;
109     }
110 }
111   
112 // Ue find the num of zeros and get (num+1) bits from the first 1, and 
113 // change it to decimal
114 // e.g. 00110 -> return 6(110)
115 UINT UDPReceiver::Ue(BYTE *pBuff, UINT nLen, UINT &nStartBit)
116 {
117     //计算0bit的个数
118     UINT nZeroNum = 0;
119     while (nStartBit < nLen * 8)
120     {
121         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余
122         {
123             break;
124         }
125         nZeroNum++;
126         nStartBit++;
127     }
128     nStartBit ++;
129   
130   
131     //计算结果
132     DWORD dwRet = 0;
133     for (UINT i=0; i<nZeroNum; i++)
134     {
135         dwRet <<= 1;
136         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
137         {
138             dwRet += 1;
139         }
140         nStartBit++;
141     }
142     return (1 << nZeroNum) - 1 + dwRet;
143 }
144   
145 int UDPReceiver::Se(BYTE *pBuff, UINT nLen, UINT &nStartBit)
146 {
147     int UeVal=Ue(pBuff,nLen,nStartBit);
148     double k=UeVal;
149     int nValue=std::ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
150     if (UeVal % 2==0)
151         nValue=-nValue;
152     return nValue;
153 }
154   
155 // u Just returns the BitCount bits of buf and change it to decimal.
156 // e.g. BitCount = 4, buf = 01011100, then return 5(0101)
157 DWORD UDPReceiver::u(UINT BitCount,BYTE * buf,UINT &nStartBit)
158 {
159     DWORD dwRet = 0;
160     for (UINT i=0; i<BitCount; i++)
161     {
162         dwRet <<= 1;
163         if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
164         {
165             dwRet += 1;
166         }
167         nStartBit++;
168     }
169     return dwRet;
170 }

从SPS帧解析视频分辨率相关推荐

  1. 解析视频分辨率和时长

    解析视频分辨率和时长 下载工具 使用的工具是:FFmpeg 分为win 和 linux 需要提前安装 FFmpeg windows版本 linux版本 有道笔记 windows 安装 将下载的进行解压 ...

  2. 【FFmpeg】java实现利用ffmpeg视频上传转码同时截取一帧保存为同名图片,并获取视频分辨率

    〇.前情提要 完成了视频上传,接下来是给上传的视频保存一张同名的jpg文件在同样文件夹中,并且获取到视频的分辨率. macOS Catalina 10.15.1 ffmpeg version 4.3. ...

  3. H264及H265 I帧解析 [转]

    H264及H265 I帧解析 [转] h264 I帧的判断 参考原文:https://blog.csdn.net/dxpqxb/article/details/13289205?utm_source= ...

  4. 解析视频编码原理——从孙艺珍的电影说起(一)

    更多博文,请看音视频系统学习的浪漫马车之总目录 视频理论基础: 视频基础知识扫盲 音视频开发基础知识之YUV颜色编码 解析视频编码原理--从孙艺珍的电影说起(一) 解析视频编码原理--从孙艺珍的电影说 ...

  5. 视频分辨率无损放大软件 Topaz Video Enhance AI 2.3.0

    视频分辨率无损放大软件 Topaz Video Enhance AI 2.3.0 Topaz Video Enhance AI是一款非常好用的视频分辨率放大软件,用户可以通过这款软件将视频的分辨率进行 ...

  6. 视频图像处理基础知识4(视频分辨率参考 行频 隔行扫描 逐行扫描)【转】

    转自:http://blog.csdn.net/Times_poem/article/details/51470065 版权声明:本文为博主原创文章,未经博主允许不得转载. 需求说明:视频处理基本知识 ...

  7. ffmpeg命令行录制一个具有非IDR性质的I帧的视频

    之前在代码上写过几篇ffmpeg桌面录制的博客,用ffprobe查看里面的帧时,全部都是IDR这种I帧,没有普通的I帧,如下所示: <frame media_type="video&q ...

  8. php获得视频分辨率,php+ffmpeg 获取视频相关信息(缩略图、视频分辨率)

    ffmpeg是一款开源.跨平台的视频处理程序,可用在Windows.mac.linux等平台,可以方便的运用多种语言脚本来调用其执行视频的操作. 下面介绍使用ffmpeg获取视频首帧的方法. & ...

  9. 视频图像处理基础知识4(视频分辨率参考 行频 隔行扫描 逐行扫描)

    需求说明:视频处理基本知识       第一部分:视频分辨率参数       第二部分:分辨率.行频.场频  第一部分:视频分辨率参数 1080p的画面分辨率为1920×1080 [视频分辨率参考]共 ...

最新文章

  1. ubuntukylin-14.04.2-desktop-amd64中python2.7版本安装机器学习库
  2. 2556. [NOIP2016]玩具谜题
  3. python判断字符大小写转换_Python 字符串大小写转换的简单实例
  4. signature=e5535ff98b93aa63c455611822dc57c2,高校新生预激综合征6例报告
  5. 乱世寻龙java_乱世王者寻龙季怎么玩?乱世王者寻龙季玩法技巧一览
  6. HihoCoder1449 后缀自动机三·重复旋律6
  7. JavaEE学习02--HTTP协议
  8. php导出word乱码,php导出的word会乱码吗
  9. 现金支票打印模板excel_Excel的正确使用技巧-Excel的提速大法
  10. 高仿QQ空间广告位 ——— 一个位置来回切换两张广告图
  11. 秦曾昌人工智能课程---7、决策树集成学习Tree Ensembles
  12. Visual Studio 2017安装使用方法
  13. 学习reflux的总结
  14. 爬取豆瓣前250电影数据
  15. 安卓系统使用外接USB声卡(XMOS)进行单声道音频数据采集
  16. usb_cam的ROS2甜点
  17. Netkiller Java 手札之前言
  18. CRM系统优化企业内控建设
  19. 最近比较火的圣诞树HTML代码
  20. Linux教程之查看文件(cat,head,tail,less,more)

热门文章

  1. 【UVA 12657】移动盒子 Boxes in a Line
  2. 一共81个,开源大数据处理工具汇总(下)转
  3. ef power tools mysql_Entity Framework Code First ---EF Power Tool 和MySql一起使用遇到的问题...
  4. python实现kmeans算法对图片的聚类分割
  5. 母牛的故事 1243ACM实验题
  6. Android系统安全 — 3.1-展锐平台secureboot安全启动流程和使用
  7. matlab实现牛顿下山法
  8. nodemon:运行提示错误:无法加载文件 xxxx
  9. html5中奖名单特效,jQuery基于json动态随机获取中奖名单抽奖代码
  10. 我的淘宝新店的辛酸与感恩