H264--语法及结构--2
---------------
前言
-------------
H264结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由16x16的yuv数据组成。宏块作为H264编码的基本单位。
-------------------------
-----------------------------------------------
H264/AVC 的分层结构
-----------------------------------------------
H.264的主要目标是:
1.高的视频压缩比;
2.良好的网络亲和性;
为了完成这些目标H264的解决方案是:
1.VCL video coding layer 视频编码层;
2.NAL network abstraction layer 网络提取层;
其中,VCL层是对核心算法引擎,块,宏块及片的语法级别的定义,他最终输出编码完的数据 SODB;
NAL层定义片级以上的语法级别(如序列参数集和图像参数集,针对网络传输),同时支持以下功能:独立片解码,起始码唯一保证,SEI以及流格式编码数据传送,NAL层将SODB打包成RBSP然后加上NAL头,组成一个NALU(NAL单元);
---------------------------------------------
H264网络传输的结构
---------------------------------------------
H264在网络传输的是NALU,NALU的结构是:NAL头+RBSP,实际传输中的数据流如图所示:
从前面的分析我们知道,VCL层出来的是编码完的视频帧数据,这些帧可能是I、B、P帧,而且这些帧可能属于不同的序列,再者同一个序列还有相对应的一套序列参数集和图片参数集等等,所以要完成视频的解码,不仅需要传输VCL层编码出来的视频帧数据,还需要传输序列参数集、图像参数集等数据。
NALU头用来标识后面的RBSP是什么类型的数据,他是否会被其他帧参考以及网络传输是否有错误。
RBSP用来存放下表中的一种:
RBSP类型 | 所写 | 描述 |
参数集 | PS | 序列的全局信息,如图像尺寸,视频格式等 |
增强信息 | SEI | 视频序列解码的增强信息 |
图像界定符 | PD | 视频图像的边界 |
编码片 | SLICE | 编码片的头信息和数据 |
数据分割 | DP片层的数据,用于错误恢复解码 | |
序列结束符 | 表明一个序列的结束,下一个图像为IDR图像 | |
流结束符 | 表明该流中已没有图像 | |
填充数据 | 亚元数据,用于填充字节 |
其中,
参数集:包括序列参数集 SPS 和图像参数集 PPS
SPS 包含的是针对一连续编码视频序列的参数,如标识符 seq_parameter_set_id、帧数及 POC 的约束、参考帧数目、解码图像尺寸和帧场编码模式选择标识等等。
PPS对应的是一个序列中某一幅图像或者某几幅图像,其参数如标识符 pic_parameter_set_id、可选的 seq_parameter_set_id、熵编码模式选择标识、片组数目、初始量化参数和去方块滤波系数调整标识等等。
数据分割:组成片的编码数据存放在 3 个独立的 DP(数据分割,A、B、C)中,各自包含一个编码片的子集。分割A包含片头和片中每个宏块头数据。分割B包含帧内和 SI 片宏块的编码残差数据。分割 C包含帧间宏块的编码残差数据。每个分割可放在独立的 NAL 单元并独立传输。
-----------------------------------------
NALU头结构
----------------------------------------
NALU头结构:nal_unit_type(5bit)+nal_reference_bit(2bit)+forbidden_bit(1bit)
1.nal_unit_type:NALU类型取值如下表所示。
nal_unit_type |
NAL类型 |
C |
0 |
未使用 |
|
1 |
非IDR图像中不采用数据划分的片段 |
2,3,4 |
2 |
非IDR图像中A类数据划分片段 |
2 |
3 |
非IDR图像中B类数据划分片段 |
3 |
4 |
非IDR图像中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.nal_reference_bit:nal重要性指示,标志该NAL单元的重要性,值越大,越重要,解码器在解码处理不过来的时候,可以丢掉重要性为0的NALU。不同类型的NALU的重要性指示如下表所示。
nal_unit_type |
NAL类型 |
nal_reference_bit |
0 |
未使用 |
0 |
1 |
非IDR的片 |
此片属于参考帧,则不等于0, 不属于参考帧,则等与0 |
2 |
片数据A分区 |
同上 |
3 |
片数据B分区 |
同上 |
4 |
片数据C分区 |
同上 |
5 |
IDR图像的片 |
5 |
6 |
补充增强信息单元(SEI) |
0 |
7 |
序列参数集 |
非0 |
8 |
图像参数集 |
非0 |
9 |
分界符 |
0 |
10 |
序列结束 |
0 |
11 |
码流结束 |
0 |
12 |
填充 |
0 |
13..23 |
保留 |
0 |
24..31 |
不保留 |
0 |
所谓参考帧,就是在其他帧解码时需要参照的帧。比如一个I帧可能被一个或多个B帧参考,一个B帧可能被某个P帧参考。
从这个表我们也可以看出来,DIR的I帧是非常重要的,他一丢,那么这个序列的所有帧都没办法解码了;然后序列参数集和图像参数集也很重要,没有序列参数集,这个序列的帧就没法解;没有图像参数集,那用到这个图像参数集的帧都没法解。
3.forbidden_bit:禁止位,初始为0,当网络发现NAL单元有比特错误时可设置该比特为1,以便接收方纠错或丢掉该单元。
-------------------------------------
NAL的开始和结束
-------------------------------
编码器将每个NAL各自独立、完整地放入一个分组,因为分组都有头部,解码器可以方便地检测出NAL的分界,并依次取出NAL进行解码。每个NAL前有一个起始码 0x00 00 01(或者0x00 00 00 01),解码器检测每个起始码,作为一个NAL的起始标识,当检测到下一个起始码时,当前NAL结束。同时H.264规定,当检测到0x000000时,也可以表征当前NAL的结束。那么NAL中数据出现0x000001或0x000000时怎么办?H.264引入了防止竞争机制,如果编码器检测到NAL数据存在0x000001或0x000000时,编码器会在最后个字节前插入一个新的字节0x03,这样:
0x000000->0x00000300
0x000001->0x00000301
0x000002->0x00000302
0x000003->0x00000303
解码器检测到0x000003时,把03抛弃,恢复原始数据。解码器在解码时,首先逐个字节读取NAL的数据,统计NAL的长度,然后再开始解码。
--------------------------------------
NALU的顺序要求
--------------------------------------
H.264/AVC标准对送到解码器的NAL单元顺序是有严格要求的,如果NAL单元的顺序是混乱的,必须将其重新依照规范组织后送入解码器,否则解码器不能够正确解码。
1.序列参数集NAL单元 必须在传送所有以此参数集为参考的其他NAL单元之前传送,不过允许这些NAL单元中间出现重复的序列参数集NAL单元。
所谓重复的详细解释为:序列参数集NAL单元都有其专门的标识,如果两个序列参数集NAL单元的标识相同,就可以认为后一个只不过是前一个的拷贝,而非新的序列参数集。
2.图像参数集NAL单元 必须在所有以此参数集为参考的其他NAL单元之前传送,不过允许这些NAL单元中间出现重复的图像参数集NAL单元,这一点与上述的序列参数集NAL单元是相同的。
3.不同基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元在顺序上不可以相互交叉,即不允许属于某一基本编码图像的一系列片段(slice)单元和数据划分片段(data partition)单元中忽然出现另一个基本编码图像的片段(slice)单元片段和数据划分片段(data partition)单元。
4.参考图像的影响:如果一幅图像以另一幅图像为参考,则属于前者的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于后者的片段和数据划分片段之后,无论是基本编码图像还是冗余编码图像都必须遵守这个规则。
5.基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于相应冗余编码图像的片段(slice)单元和数据划分片段(data partition)单元之前。
6.如果数据流中出现了连续的无参考基本编码图像,则图像序号小的在前面。
7.如果arbitrary_slice_order_allowed_flag置为1,一个基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元的顺序是任意的,如果arbitrary_slice_order_allowed_flag置为零,则要按照片段中第一个宏块的位置来确定片段的顺序,若使用数据划分,则A类数据划分片段在B类数据划分片段之前,B类数据划分片段在C类数据划分片段之前,而且对应不同片段的数据划分片段不能相互交叉,也不能与没有数据划分的片段相互交叉。
8.如果存在SEI(补充增强信息)单元的话,它必须在它所对应的基本编码图像的片段(slice)单元和数据划分片段(data partition)单元之前,并同时必须紧接在上一个基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元后边。假如SEI属于多个基本编码图像,其顺序仅以第一个基本编码图像为参照。
9.如果存在图像分割符的话,它必须在所有SEI 单元、基本编码图像的所有片段slice)单元和数据划分片段(data partition)单元之前,并且紧接着上一个基本编码图像那些NAL单元。
10.如果存在序列结束符,且序列结束符后还有图像,则该图像必须是IDR(即时解码器刷新)图像。序列结束符的位置应当在属于这个IDR图像的分割符、SEI 单元等数据之前,且紧接着前面那些图像的NAL单元。如果序列结束符后没有图像了,那么它的就在比特流中所有图像数据之后。
11.流结束符在比特流中的最后。
H264--语法及结构--2相关推荐
- 音视频开发之旅(56) -H264/AVC基本结构
从这篇开始,我们进入H264的学习实践,主要分三个阶段 学习H264基本结构: 了解具体编码压缩技术: 分析了解相关开源库 x264和h264bitstream. 这篇我们来一起学习H264的基本结构 ...
- MySQL 高级 - 存储过程 - 语法 - case结构
MySQL 高级 - 存储过程 - 语法 - case结构 -- 给定一个月份, 然后计算出所在的季度 create procedure pro_test7(mon int) begindeclare ...
- drools快速入门:简介、语法和结构
目录 简介 使用场景 语法和结构 大致结构 Attribute常见属性介绍 when和then语法介绍 启动运行drools代码 pom依赖 简介 drools规则引擎,官网地址:Drools - D ...
- javascript基础语法——词法结构
前面的话 javascript是一门简单的语言,也是一门复杂的语言.说它简单,是因为学会使用它只需片刻功夫:而说它复杂,是因为要真正掌握它则需要数年时间.实际上,前端工程师很大程度上就是指javasc ...
- 【Python】语法基本结构
目录 程序运行三大结构流程: 逻辑运算符: if语句的定义和结构: if语句的定义: if语句的分支结构设计: if语句的嵌套: 循环结构: 循环的定义和结构: 循环嵌套: 程序运行 ...
- CSS-5 列表元素(ol+ul++li+dl+dt+dd)、表格元素、单元格合并、表单元素(input+label+radio+...)、Emmet语法、结构伪类(:nth-child)
目录 1_列表元素 1.1_列表的实现方式 1.2_有序列表 – ol – li 1.3_无序列表 – ul - li 1.4_定义列表 – dl – dt - dd 1.5_ 写前端代码逻辑顺序 2 ...
- IOS开发语言OC的基本语法以及结构
Objective-C语法之Objective-C语言和IOS系统(简介,语法,系统结构) 简介 Objective-C,是扩充C的面向对象编程语言.它主要使用于Mac OS Objective-C, ...
- Java基础语法-条件结构-switch条件结构
1.什么是switch条件结构 switch 条件结构的使用是搭配 case 关键字来使用的. 表示 判断一个变量与一系列值中的某个值是否相等,其中每个值称为一个分支. 2.switch的语法结构 s ...
- 刘晓艳2021英语语法句型结构总结1之简单句型结构
p1-英语的五大句型结构 句子的所有结构: 1.主谓 2.主谓宾 3.主谓表(主系表) 4.主谓双宾:he teaches **us English ** // he gave **me ** fiv ...
- java单分支结构,java基础语法分支结构
java分支结构有两种: 1,if语句, 2,switch语句 if语句 格式一: if(条件表达式){ 执行代码块; } [当条件表达式的结果为true时,执行代码块] 例: if(11> ...
最新文章
- Dubbo架构设计详解--转载
- 【SAP干货】创建Search Helps (Elementary and Secondary)
- 2017年你会花钱在线听歌吗?
- 制造机器人的现状和发展趋势
- Orleans稍微复杂的例子—互动
- Java8新特性:使用Stream流递归实现遍历树形结构
- linux加水印乱码,linux java程序加水印及中文乱码方案(二)
- 剑指offer面试题[59]-对称的二叉树
- 23种设计模式(0)——概述
- 车牌识别LPR(八)-- 字符识别
- 大学高数常微分方程思维导图_思维导图_2016考研数学:高数中六种常见题型归纳_沪江英语...
- 龙帝国与避风港最新网址
- java随机产生long_java生成随机数
- 个人邮箱地址格式,如何能够正确的书写?
- linux实用教程复习题,linux上机复习题(部分答案)
- Hibernate VS iBATIS (转自ITEYE davy)
- mysql rman_利用RMAN把ORACLE10G64位降级为32位_MySQL
- linux 网络慢 dns,Linux DNS客户端解析域名慢解决
- Linux获取纳秒级时间,WINDOW和LINXU下获取纳秒级时间精度
- python阿里巴巴排名_全自动监控网页关键词排名(Python实现)
热门文章
- 蓝点中文Linux2.0 实验十三 进程与作业管理
- conda create出现连接问题_解决conda创建新环境慢 conda install 速度慢 报错问题
- 通过Spring @PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
- disruptor:CAS实现高效(伪)无锁阻塞队列实践
- TP-Link C2和C20i产品出现命令注入、DoS等多个漏洞 绿盟科技发布安全威胁通告
- 深入理解javascript中的立即执行函数(function(){…})() 1
- Effective C++ 之 Item 5:了解C++默默编写并调用哪些函数
- Memcached:高性能分布式对象缓存系统
- SpringSecurity3.0.4的An AuthenticationManager is...
- 年终个人总结:我这五年