H264实时编码及NALU,RTP传输(ZZ)

rfc3984
Standards Track [Page 2] RFC 3984 RTP Payload Format for H.264 Video February 2005 1.
按照RFC3984协议实现H264视频流媒体

nalu单元 包起始 0x 00 00 00 01

H.264 NAL格式及分析器
http://hi.baidu.com/zsw%5Fdavy/b ... c409cc7cd92ace.html
http://hi.baidu.com/zsw_davy/blo ... 081312c8fc7acc.html

----------------------------------比特流信息----------------------------------------------

①NALU(Network Abstract Layer Unit):两标准中的比特流都是以NAL为单位,每个NAL单元包含一个RBSP,NALU的头信息定义了RBSP所属类型。类型一般包括序列参数集(SPS)、图像参数集(PPS)、增强信息(SEI)、条带(Slice)等,其中,SPS和PPS属于参数集,两标准采用参数集机制是为了将一些主要的序列、图像参数(解码图像尺寸、片组数、参考帧数、量化和滤波参数标记等)与其他参数分离,通过解码器先解码出来。此外,为了增强图像的清晰度,AVS-M添加了图像头(Picture head)信息。读取NALU流程中,每个NALU前有一个起始码0x000001,为防止 内部0x000001序列竞争,H.264编码器在最后一字节前插入一个新的字节——0x03,所以解码器检测到该序列时,需将0x03删掉,而AVS-M只需识别出起始码0x000001。


②读取宏块类型(mb type)和宏块编码模板(cbp):编解码图像以宏块划分,一个宏块由一个16*16亮度块和相应的一个8*8cb和一个8*8cr色度块组成。


(a) 两标准的帧内、帧间预测时宏块的划分是有区别的。H.264中,I_slice亮度块有Intra_4*4和Intra_16*16两种模式,色度块只有8*8模式;P_slice宏块分为16*16、16*8、8*16、8*8、8*4、4*8、4*4共7种模式。而AVS-M中,I_slice亮度块有I_4*4和I_Direct两模式,P_slice时宏块的划分和H.264中的划分一致。


(b) 两标准的宏块cbp值计算也不相同。H.264中,Intra_16*16宏块的亮度(色度)cbp直接通过读mb type得到;非Intra_16*16宏块的亮度cbp=coded_block_pattern%16,色度cbp=coded_block_pattern/16 。其中,亮度cbp最低4位有效,每位决定对应宏块的残差系数能不能为0;色度cbp为0时,对应残差系数为0,cbp为1时,DC残差系数不为0,AC系数为0,cbp为2时,DC、AC残差系数都不为0。AVS-M中,当宏块类型不是P_skip时,直接从码流中得到cbp的索引值,并以此索引值查表得到codenum值,再以codenum查表分别得到帧内/帧间cbp。此cbp为6位,每位代表宏块按8*8划分时能不能包含非零系数,当变换系数不为0时,需进一步读cbp_4*4中每位值来判断一个8*8块中4个4*4块的系数能不能为0。
---------------------------------------------------------------------------------------------
总的来说H264的码流的打包方式有两种,一种为annex-b byte stream format的格式,这个是绝大部分编码器的默认输出格式,就是每个帧的开头的3~4个字节是H264的start_code,0x00000001或者0x000001。
另一种是原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编码器的profile,level,PPS,SPS等信息才可以解码。
----------------------------------------------------------------------------
AVC vs. H.264
AVC and H.264 are synonymous. The standard is known by the full names "ISO/IEC 14496-10" and "ITU-T Recommendation H.264". In addition, a number of alternate names are used (or have been) in reference to this standard. These include:


  • MPEG-4 part 10
  • MPEG-4 AVC
  • AVC
  • MPEG-4 (in the broadcasting world MPEG4 part 2 is ignored)
  • H.264
  • JVT (Joint Video Team, nowadays rarely used referring to actual spec)
  • H.26L (early drafts went by this name)

All of the above (and those I've missed) include the Annex B byte-stream format. Unlike earlier MPEG1/2/4 and H.26x codecs, the H.264 specification proper does not define a full bit-stream syntax. It describes a number of NAL (Network Abstraction Layer) units, a sequence of which can be decoded into video frames. These NAL units have no boundary markers, and rely on some unspecified format to provide framing.

Annex B of of the document specifies one such format, which wraps NAL units in a format resembling a traditional MPEG video elementary stream, thus making it suitable for use with containers like MPEG PS/TS unable to provide the required framing. Other formats, such as ISO base media based formats, are able to properly separate the NAL units and do not need the Annex B wrapping.

The H.264 spec suffers from a deficiency. It defines several header-type NAL units (SPS and PPS) without specifying how to pack them into the single codec data field available in most containers. Fortunately, most containers seem to have adopted the packing used by the ISO format known as MP4.
1. H.264起始码
   在网络传输h264数据时,一个UDP包就是一个NALU,解码器可以很方便的检测出NAL分界和解码。但是如果编码数据存储为一个文件,原来的解码器将无法从数据流中分别出每个NAL的起始位置和终止位置,为此h.264用起始码来解决这一问题。

   H.264编码时,在每个NAL前添加起始码 0x000001,解码器在码流中检测到起始码,当前NAL结束。为了防止NAL内部出现0x000001的数据,h.264又提出'防止竞争 emulation prevention"机制,在编码完一个NAL时,如果检测出有连续两个0x00字节,就在后面插入一个0x03。当解码器在NAL内部检测到0x000003的数据,就把0x03抛弃,恢复原始数据。
0x000000   >>>>>>   0x00000300
0x000001   >>>>>>   0x00000301
0x000002   >>>>>>   0x00000302
0x000003   >>>>>>   0x00000303

附上h.264解码nalu中检测起始码的算法流程  
for(;;)
{
if next 24 bits are 0x000001
{
       startCodeFound = true
       break;
}
else
{
       flush 8 bits  
}
}// for(;;)
if(true == startCodeFound)
{
    //startcode found
    // Flush the start code found
    flush 24 bits  
    //Now navigate up to next start code and put the in between stuff
    // in the nal structure.
    for(;;)
    {
      get next 24 bits & check if it equals to 0x000001
      if(false == (next 24 bits == 000001))
      {
         // search for pattern 0x000000
         check if next 24 bits are 0x000000
         if(false == result)
         {
                // copy the byte into the buffer
                copy one byte to the Nal unit             
         }
         else
         {
                break;
         }
      }
      else
      {
             break;
      }
   }//for(;;)
}

   2. MPEG4起始码
       MPEG4的特色是VOP,没有NALU的概念,仍使用startcode对每帧进行分界。MPEG4的起始码是0x000001. 另外MPEG4中很多起始码也很有用,比如video_object_sequence_start_code 0x000001B0 表示一个视频对象序列的开始,VO_start_code 0x000001B6 表示一个VOP的开始. 0x000001B6之后的两位,是00表示 I frame, 01 表示 P frame, 10 表示 B frame.
1.引言

H.264的主要目标:

1.高的视频压缩比

2.良好的网络亲和性

解决方案:

VCL   video coding layer    视频编码层

NAL   network abstraction layer   网络提取层

VCL:核心算法引擎,块,宏块及片的语法级别的定义

NAL:片级以上的语法级别(如序列参数集和图像参数集),同时支持以下功能:独立片解码,起始码唯一保证,SEI以及流格式编码数据传送

VCL设计目标:尽可能地独立于网络的情况下进行高效的编解码

NAL设计目标:根据不同的网络把数据打包成相应的格式,将VCL产生的比特字符串适配到各种各样的网络和多元环境中。

NALU头结构:NALU类型(5bit)、重要性指示位(2bit)、禁止位(1bit)。

NALU类型:1~12由H.264使用,24~31由H.264以外的应用使用。

重要性指示:标志该NAL单元用于重建时的重要性,值越大,越重要。

禁止位:网络发现NAL单元有比特错误时可设置该比特为1,以便接收方丢掉该单元。

2.NAL语法语义

NAL层句法:

在编码器输出的码流中,数据的基本单元是句法元素。

句法表征句法元素的组织结构。

语义阐述句法元素的具体含义。

分组都有头部,解码器可以很方便的检测出NAL的分界,依次取出NAL进行解码。

但为了节省码流,H.264没有另外在NAL的头部设立表示起始位置的句法元素。

如果编码数据是存储在介质上的,由于NAL是依次紧密相连的,解码器就无法在数据流中分辨出每个NAL的起始位置和终止位置。

解决方案:在每个NAL前添加起始码:0X000001

在某些类型的介质上,为了寻址的方便,要求数据流在长度上对齐,或某个常数的整数倍。所以在起始码前添加若干字节的0来填充。

检测NAL的开始:

0X000001和0X000000

我们必须考虑当NAL内部出现了0X000001和0X000000

解决方案:

H.264提出了“防止竞争”机制:

0X000000——0X00000300

0X000001——0X00000301

0X000002——0X00000302

0X000003——0X00000303

为此,我们可以知道:

在NAL单元中,下面的三字节序列不应在任何字节对齐的位置出现

0X000000

0X000001

0X000002

Forbidden_zero_bit =0;

Nal_ref_idc:表示NAL的优先级。0~3,取值越大,表示当前NAL越重要,需要优先受到保护。如果当前NAL是属于参考帧的片,或是序列参数集,或是图像参数集这些重要的单位时,本句法元素必需大于0。

Nal_unit_type:当前NAL 单元的类型

3.H.264的NAL层处理

结构示意图:

NAL以NALU(NAL unit)为单元来支持编码数据在基于分组交换技术网络中传输。

它定义了符合传输层或存储介质要求的数据格式,同时给出头信息,从而提供了视频编码和外部世界的接口。

NALU:定义了可用于基于分组和基于比特流系统的基本格式

RTP封装:只针对基于NAL单元的本地NAL接口。

三种不同的数据形式:

SODB 数据比特串-->最原始的编码数据

RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若干比特“0”,以便字节对齐

EBSP 扩展字节序列载荷-->在RBSP基础上填加了仿校验字节(0X03)它的原因是: 在NALU加到Annexb上时,需要添加每组NALU之前的开始码StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示ox000001.为了使NALU主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03去掉。也称为脱壳操作

处理过程:

1.   将VCL层输出的SODB封装成nal_unit, Nal_unit是一个通用封装格式,可以适用于有序字节流方式和IP包交换方式。

2.   针对不同的传送网络(电路交换|包交换),将nal_unit 封装成针对不同网络的封装格    式。



第一步的具体过程:

VCL层输出的比特流SODB(String Of Data Bits),到nal_unit之间,经过了以下三步处理:

1.SODB字节对齐处理后封装成RBSP(Raw Byte Sequence Payload)。

2.为防止RBSP的字节流与有序字节流传送方式下的SCP(start_code_prefix_one_3bytes,0x000001)出现字节竞争情形,循环检测RBSP前三个字节,在出现字节竞争时在第三字节前加入emulation_prevention_three_byte (0x03),具体方法:

nal_unit( NumBytesInNALunit ) {

forbidden_zero_bit

nal_ref_idc

nal_unit_type

NumBytesInRBSP = 0

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

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

rbsp_byte[ NumBytesInRBSP++ ]

rbsp_byte[ NumBytesInRBSP++ ]

i += 2

emulation_prevention_three_byte /* equal to 0x03 */

} else

rbsp_byte[ NumBytesInRBSP++ ]

}

}

3. 防字节竞争处理后的RBSP再加一个字节的header(forbidden_zero_bit+ nal_ref_idc+ nal_unit_type),封装成nal_unit.

第二步的具体过程:



case1:有序字节流的封装



byte_stream_nal_unit( NumBytesInNALunit ) {

while( next_bits( 24 ) != 0x000001 )

zero_byte /* equal to 0x00 */

if( more_data_in_byte_stream( ) ) {

start_code_prefix_one_3bytes /* equal to 0x000001 */ nal_unit( NumBytesInNALunit )

}

}

类似H.320和MPEG-2/H.222.0等传输系统,传输NAL作为有序连续字节或比特流,同时要依靠数据本身识别NAL单元边界。在这样的应用系统中,H.264/AVC规范定义了字节流格式,每个NAL单元前面增加3个字节的前缀,即同步字节。在比特流应用中,每个图像需要增加一个附加字节作为边界定位。还有一种可选特性,在字节流中增加附加数据,用做扩充发送数据量,能实现快速边界定位,恢复同步

Case2:IP网络的RTP打包封装

分组打包的规则

(1)额外开销要少,使MTU尺寸在100~64k字节范围都可以;

(2)不用对分组内的数据解码就可以判别该分组的重要性;

(3)载荷规范应当保证不用解码就可识别由于其他的比特丢失而造成的分组不可解码;

(4)支持将NALU分割成多个RTP分组;

    (5)支持将多个NALU汇集在一个RTP分组中。

RTP的头标可以是NALU的头标,并可以实现以上的打包规则。

一个RTP分组里放入一个NALU,将NALU(包括同时作为载荷头标的NALU头)放入RTP的载荷中,设置RTP头标值。为了避免IP层对大分组的再一次分割,片分组的大小一般都要小于MTU尺寸。由于包传送的路径不同,解码端要重新对片分组排序,RTP包含的次序信息可以用来解决这一问题。

NALU分割

对于预先已经编码的内容,NALU可能大于MTU尺寸的限制。虽然IP层的分割可以使数据块小于64千字节,但无法在应用层实现保护,从而降低了非等重保护方案的效果。由于UDP数据包小于64千字节,而且一个片的长度对某些应用场合来说太小,所以应用层打包是RTP打包方案的一部分。

新的讨论方案(IETF)应当符合以下特征:

(1)NALU的分块以按RTP次序号升序传输;

(2)能够标记第一个和最后一个NALU分块;

(3)可以检测丢失的分块。

NALU合并

一些NALU如SEI、参数集等非常小,将它们合并在一起有利于减少头标开销。已有两种集合分组:

(1)单一时间集合分组(STAP),按时间戳进行组合;

(2)多时间集合分组(MTAP),不同时间戳也可以组合。

NAL规范视频数据的格式,主要是提供头部信息,以适合各种媒体的传输和存储。NAL支持各种网络,包括:

1.任何使用RTP/IP协议的实时有线和无线Internet 服务

2.作为MP4文件存储和多媒体信息文件服务

3.MPEG-2系统

4.其它网

NAL规定一种通用的格式,既适合面向包传输,也适合流传送。实际上,包传输和流传输的方式是相同的,不同之处是传输前面增加了一个起始码前缀

在类似Internet/RTP面向包传送协议系统中,包结构中包含包边界识别字节,在这种情况下,不需要同步字节。

NAL单元分为VCL和非VCL两种

VCL NAL单元包含视频图像采样信息,

非VCL包含各种有关的附加信息,例如参数集(头部信息,应用到大量的VCL NAL单元)、提高性能的附加信息、定时信息等

参数集:

参数集是很少变化的信息,用于大量VCL NAL单元的解码,分为两种类型:

1.序列参数集,作用于一串连续的视频图像,即视频序列。

两个IDR图像之间为序列参数集。IDR和I帧的区别见下面。

2.   图像参数集,作用于视频序列中的一个或多个个别的图像

序列和图像参数集机制,减少了重复参数的传送,每个VCL NAL单元包含一个标识,指

向有关的图像参数集,每个图像参数集包含一个标识,指向有关的序列参数集的内容

因此,只用少数的指针信息,引用大量的参数,大大减少每个VCL NAL单元重复传送的信息。

序列和图像参数集可以在发送VCL NAL单元以前发送,并且重复传送,大大提高纠错能力。序列和图像参数集可以在“带内”,也可以用更为可靠的其他“带外”通道传送。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/455584.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习具体计划书

计划书10大行动&#xff1a;1. 学习的时候不玩手机学习的时候把手机放在抽屉里&#xff0c;静音2. 及时复习学完一个章节的知识及时复习觉得有做分享的价值就做分享录视频3. 不学习的时间要好好利用花时间做好吃的&#xff0c;把身体弄好多看看心理学的书&#xff0c;<接触青…

初识python

课程介绍: python语言:python语言是一种计算机程序设计语言,实现人机交互的语言 python的课程设计python基础 (python开发工程师)数据库和SQL开发 (数据分析工程师)网络爬虫 (网络爬虫工程师)高数和数据分析 (数据分析工程师)人工智能和机器学习 …

photoshop最全快捷键列表

一、工具箱(多种工具共用一个快捷键的可同时按【Shift】加此快捷键选取) 矩形、椭圆选框工具 【M】 移动工具 【V】 套索、多边形套索、磁性套索 【L】 魔棒工具 【W】 裁剪工具 【C】 切片工具、切片选择工具 【K】 喷枪工具 【J】 画笔工具、铅笔工具 【B】 像皮图章、图案图…

python实例化对象做实参_如何在Python中记住类实例化?

好的&#xff0c;这是真实的场景&#xff1a;我正在编写一个应用程序&#xff0c;我有一个类&#xff0c;它表示某种类型的文件&#xff08;在我的例子中&#xff0c;这是照片&#xff0c;但细节与问题无关&#xff09;。照片类的每个实例对于照片的文件名都应该是唯一的。 问题…

bupt summer training for 16 #3 ——构造

https://vjudge.net/contest/172464 后来补题发现这场做的可真他妈傻逼 A.签到傻逼题&#xff0c;自己分情况 1 #include <cstdio>2 #include <vector>3 #include <algorithm>4 5 using std::vector;6 using std::sort;7 8 typedef long long ll;9 10 int n…

Python02期(北京)课程笔记索引

day01 初始python关于使用notepad运行python程序注释和语句分类 day02 命名方式和关键字数据类型数据类型转换 day03 变量与数据类型运算和运算符进制转换 day04 循环结构 day05 函数概述 day06 nonlocal和global 关键字详解 day07 python核心,内建函数高阶函数字…

python常用快捷键、写代码事半功倍_Pycharm常用快捷键总结及配置方法

工欲善其事必先利其器&#xff0c;Python开发利器Pycharm常用快捷键以及配置如下&#xff0c;相信有了这些快捷键&#xff0c;你的开发会事半功倍 一 常用快捷键 编辑类&#xff1a; Ctrl D 复制选定的区域或行 Ctrl Y 删除选定的行 Ctrl Alt L 代码格式化 Ctrl Alt O 优…

PHP中的魔术常量

魔术常量 PHP 向它运行的任何脚本提供了大量的预定义常量。不过很多常量都是由不同的扩展库定义的&#xff0c;只有在加载了这些扩展库时才会出现&#xff0c;或者动态加载后&#xff0c;或者在编译时已经包括进去了。 有八个魔术常量它们的值随着它们在代码中的位置改变而改…

Java中的继承性特性

继承性是java中的第二特性之一。而继承性最为关键的地方为&#xff1a;代码重用性的问题&#xff0c;利用继承性可以从已有的类中继续派生出新的子类&#xff0c;也可以利用子类扩展出更多的操作功能。 继承性的实现代码为&#xff1a;class 子类 extends 父类{ } 有以下3点说…

10大html5前端框架

Bootstrap 首先说 Bootstrap&#xff0c;估计你也猜到会先说或者一定会有这个( 呵呵了 )&#xff0c;这是说明它的强大之处&#xff0c;拥有框架一壁江山的势气。自己刚入道的时候本着代码任何一个字母都得自己敲出来挡我者废的决心&#xff0c;来让自己成长。结果受到周围各 种…

多媒体技术复习汇总 收藏

多媒体技术复习汇总 收藏 1. 什么是媒体&#xff1a;媒体是信息表示和传输的载体。2. 媒体分类&#xff1a;感觉媒体&#xff0c;表示媒体&#xff0c;表现媒体&#xff0c;存储媒体&#xff0c;传输媒体3. 多媒体技术的定义和特点&#xff1a;多媒体技…

PHP中的语法特点小结

PHP中的语法特点小结 1.PHP的变量开头要加上$符号,见到$就知道这个是一个变量 2.PHP中的常量才是不用加$符号的 3.PHP中$可以用来嵌套使用,从而实现动态的变量名的层级调用 4.PHP程序<?php开头,结尾可以加上?>,也可以不加 5.PHP中的常量有着魔术常量(系统自带的) 6.PH…

滚动行为

new router({ scrollBehavior (to, from, savaPosition) { if(savePosition) { //历史记录的前进后退记住的之前滚动到的位置 return savePosition } else { return {x: 0, y: 0} } //history模式下 定位到某个元素失效的解决办法 if(to.hash) { return { selector: to.h…

使用FFMPEG SDK解码流数据获得YUV数据及其大小

本文以H264视频流为例&#xff0c;讲解解码流数据的步骤。 为突出重点&#xff0c;本文只专注于讨论解码视频流数据&#xff0c;不涉及其它&#xff08;如开发环境的配置等&#xff09;。如果您需要这方面的信息&#xff0c;请和我联系。 准备变量 定义AVCodecContext。如果您…

关于Python3.7和Python3.6中元组类型数据内存存储问题

关于Python3.7和Python3.6中元组类型数据内存存储问题 小编最近发现了一个瑕疵 当定义一个元组类型的变量后,若在程序后面再定义一个元组变量,这两个元组的内容相同,那么在不同的版本中会出现不同的结果 在Python3.6版本中,解释器将在内存中开辟两个内存空间分别存储两个元组的…

shell 删除了hdfs 文件_从零开始学大数据(三) Shell操作HDFS文件系统-中

1、格式化[rootmaster sbin]# hdfs namenode -format2、命令hdfs dfsadmin查看(hdfs dfsadmin -report)[rootmaster ~]# hdfs dfsadmin -report安全模式#获取安全模式状态[rootmaster ~]# hdfs dfsadmin -safemode get#进入安全状态[rootmaster ~]# hdfs dfsadmin -safemode en…

计算机硬件

计算机硬件 一、为什么要学习计算机基础 程序员编程的本质就是让计算机去工作&#xff0c;而编程语言就是程序员与计算机沟通的介质。程序员要想让计算机工作&#xff0c;就要知道计算机能干什么、是怎么样的一个完成过程&#xff0c;这也是我们必须学习计算机基础的原因。 …

当编程作为一种爱好

一、当编程作为一种爱好&#xff0c;时刻关心一段代码如何实现。 二、当把工具操作得足够熟悉&#xff0c;闭眼即能达到代码述写的规范。 三、程序呀&#xff0c;如果爱上你是我的错&#xff0c;我打算一错到底。转载于:https://www.cnblogs.com/spiriter88/p/6913539.html

Python中的函数概述

1.python中函数概述 概念 模块化编程的思想 有组织,可共享(重复使用,实现特定的功能的代码块) 提高程序的可维护性,提高开发效率,提高代码的重用性定义一个函数 1.语法:def 函数名称(形参列表):函数体/代码块return 返回值 2.定义参数介绍 def :关键字 用于函数的定义,函数的…

铁路售票系统_铁路资讯:复兴号动车、智能京张高铁…中国最高端铁路装备看这里...

今天上午&#xff0c;两年一度的中国国际现代化铁路技术装备展在京开展&#xff0c;会期3天&#xff0c;将集中展示路网建设、客货运输、经营管理、工程建造、技术装备、旅客服务等铁路行业各领域的先进产品及技术。展会现场智能京张&#xff1a;将首次实现时速350公里自动驾驶…