ffmpeg 从mp4上提取H264的nalu
http://blog.csdn.net/gavinr/article/details/7183499
639 /* bitstream filters */
640 REGISTER_BSF(AAC_ADTSTOASC, aac_adtstoasc);
641 REGISTER_BSF(CHOMP, chomp);
642 REGISTER_BSF(DUMP_EXTRADATA, dump_extradata);
643 REGISTER_BSF(H264_MP4TOANNEXB, h264_mp4toannexb);
644 REGISTER_BSF(HEVC_MP4TOANNEXB, hevc_mp4toannexb);
645 REGISTER_BSF(IMX_DUMP_HEADER, imx_dump_header);
646 REGISTER_BSF(MJPEG2JPEG, mjpeg2jpeg);
647 REGISTER_BSF(MJPEGA_DUMP_HEADER, mjpega_dump_header);
648 REGISTER_BSF(MP3_HEADER_DECOMPRESS, mp3_header_decompress);
649 REGISTER_BSF(MPEG4_UNPACK_BFRAMES, mpeg4_unpack_bframes);
650 REGISTER_BSF(MOV2TEXTSUB, mov2textsub);
651 REGISTER_BSF(NOISE, noise);
652 REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata);
653 REGISTER_BSF(TEXT2MOVSUB, text2movsub);
annex-b格式
http://blog.sina.com.cn/s/blog_5f435c1301015oxp.html
H264码流的NAL起始字节分析
这是一段H264码流,00 00 00 01这是对应forbidden_zero_bit的f(1),接着后面的nal_ref_idc的u(2),这个怎么解呀,有点晕。刚接触不久,nal_unit_type的u(5),后面的profile_idc的u(8)指的是那几个,是多少?
问题补充:
nal_ref_idc的u(2)对应67变成前两位0 1也就是1,nal_unit_type取64接着的5位 10 01 1则组合成19 ,profile_idc的u(8)则是后面的64转化为十进制则是100,level_idc则是0D是13,seq_parameter_set_id的ue(v),则指到AC了,这是哥伦布编码,答案是0,这个是怎么算出来的?
满意回答
00 00 00 01是Start code后面的ox67为 0110 0111
forbidden_zero_bit 是禁止位,应该是第一位即f(1)=0,1为语法有错误
nal_ref_idc是参考级别,代表被其它帧参考情况,u(2)= 11 = 3最(0为无参考,详见规范)
nal_unit_type是该帧的类型,为剩下的5位,u(5)= 0 0111 = 7
目前类型有:
//H264定义的类型 values for nal_unit_type
typedef enum {
NALU_TYPE_SLICE = 1,
NALU_TYPE_DPA = 2,
NALU_TYPE_DPB = 3,
NALU_TYPE_DPC = 4,
NALU_TYPE_IDR = 5,
NALU_TYPE_SEI = 6,
NALU_TYPE_SPS = 7,
NALU_TYPE_PPS = 8,
NALU_TYPE_AUD = 9,
NALU_TYPE_EOSEQ = 10,
NALU_TYPE_EOSTREAM = 11,
NALU_TYPE_FILL = 12,
#if (MVC_EXTENSION_ENABLE)
NALU_TYPE_PREFIX = 14,
NALU_TYPE_SUB_SPS = 15,
NALU_TYPE_SLC_EXT = 20,
NALU_TYPE_VDRD = 24 // View and Dependency Representation Delimiter NAL Unit
#endif
} NaluType;
可以看出是NALU_TYPE_SPS 即sequence parameter sets
profile_idc的u(8)则是后面的64转化为十进制则是100,
66 Baseline
77 Main
88 Extended
100 High (FRExt)
110 High 10 (FRExt)
122 High 4:2:2 (FRExt)
144 High 4:4:4 (FRExt)
100是High (FRExt)
“level_idc则是0D是13,seq_parameter_set_id的ue(v),则指到AC了,这是哥伦布编码,答案是0,这个是怎么算出来的?“
就不太懂了。互相帮忙吧。
赞同
8
| 评论(1)
擅长领域: 暂未定制
参加的活动: 暂时没有参加的活动
提问者对于答案的评价:
还是蛮感谢的,挺详细的!
最近在学习的h264视频流的以.flv文件格式存盘。
在收到h264码流的每个NAL数据(Buffer指针)时,对于如下代码的理解:
if((*(Buffer) == 0) && (*(Buffer+1) == 0) && (*(Buffer+2) == 0) && (*(Buffer+3) == 1)) //NAL头的0x00 00 00 01起始码
{
if(*(Buffer+4) == SPS_FRAME)
{ //ox67为 0110 0111(nal_unit_type为低5位,u(5)= 0 0111 = 7)
frame_type = SPS_FRAME;
}
else if(*(Buffer+4) == PPS_FRAME)
{ //ox68为 0110 1000 (nal_unit_type为低5位,u(5)= 0 1000 = 8)
frame_type = PPS_FRAME;
}
else if(*(Buffer+4) == I_FRAME)
{ //ox65为 0110 0101 (nal_unit_type为低5位,u(5)= 0 0101 = 5)
frame_type = I_FRAME;
}
else
{ //0x41为0100 00001 (nal_ref_idc是参考级别,代表被其它帧参考情况,u(2)= 10 = 2; nal_unit_type为低5位,u(5)= 0 0001 = 1)
frame_type = P_FRAME;
}
if((*(Buffer+5) & 0x80) == 0x80)
{
start_frame = 1;
}
}
h264 图像、帧、片、NALU
http://blog.csdn.net/zqnihao917/article/details/7760170
(1)、在 H.264协议中图像是个集合概念,顶场、底场、帧都可以称为图像(本文图像概念时都是集合概念)。因此我们可以知道,对于H.264 协议来说,我们平常所熟悉的那些称呼,例如:I 帧、P 帧、B帧等等,实际上都是我们把图像这个概念具体化和细小化了。我们在 H.264里提到的“帧”通常就是指不分场的图像;
(2)、如果不采用FMO(灵活宏块排序) 机制,则一幅图像只有一个片组;
(3)、如果不使用多个片,则一个片组只有一个片;
(4)、如果不采用DP(数据分割)机制,则一个片就是一个NALU,一个 NALU 也就是一个片。
3 编码条带数据分割块Bslice_data_partition_b_layer_rbsp( )
4 编码条带数据分割块Cslice_data_partition_c_layer_rbsp( )
一幅图像根据组成它的片类型来分,可以分为标准“表7-5”中的 8种类型。我们平常应用中所最常见到的其实是这些类型的特例。例如:我们平常所谓的“I帧”和“IDR 帧”,其实是 primary_pic_type 值为 0的图像,我们平常所谓的“P帧”其实是 primary_pic_type 值为
1的图像的特例,我们平常所谓的“B帧”其实是 primary_pic_type 值为 2的图像的特例。
一幅图像根据概念来分可以分为两种:IDR 图像和非 IDR图像。一幅图像是否是 IDR 图像是由组成该图像的 NALU决定的,如果组成该图像的 NALU 为标准“表7-1”中 nal_unit_type 值为 5 的NALU,则该图像为 IDR 图像,否则为非
IDR图像。这里也有几点值得说明:
(2)、我们以组成一幅图像的片的类型来区分该图像是否是IDR 图像是错误的。
一幅图像由 1~N个片组组成,而每一个片组又由一个或若干个片组成一个片由一个NALU或三个NALU(假如有数据分割)组成。图像解码过程中总是按照片进行解码,然后按照片组将解码宏块重组成图像。从这种意义上讲,片实际是最大的解码单元。
标准“表7-18”做了最好的说明。
怎么区分H.264视频流的I frame 和 Pframe? 收藏
怎么区分H.264视频流的I frame 和 P frame?
我是新手,前些天自己看那H.264规范文档及其他资料寻找答案时,
还有几个概念的关系还没能理解清楚,望达人指点一二:
NAL、Slice与frame意思及相互关系
NALnal_unit_type中的1(非IDR图像的编码条带)、2(编码条带数据分割块A)、3(编码条带数据分割块B)、4(编码条带数据分割块C)、5(IDR图像的编码条带)种类型
与
Slice种的三种编码模式:I_slice、P_slice、B_slice
还有frame的3种类型:I frame、P frame、 B frame之间有什么映射关系么?
最后,NAL nal_unit_type中的6(SEI)、7(SPS)、8(PPS)属于什么帧呢?
---------------------------------------------------------------------------
1 frame的数据可以分为多个slice.
每个slice中的数据,在帧内预测只用到自己slice的数据, 与其他slice数据没有依赖关系。
NAL 是用来将编码的数据进行大包的。 比如,每一个slice 数据可以放在NAL 包中。
I frame 是自己独立编码,不依赖于其他frame 数据。
P frame 依赖 I frame 数据。
B frame 依赖 I frame, P frame 或其他 B frame 数据。
----------------------------------------------------------------------------
那NAL nal_unit_type中的哪几种类型是Iframe,现在只能确定nal_unit_type==5(IDR图像的编码条带)是I frame
sps、pps、SEI算不算I frame呢? 还有 属于编码条带分割的DPA、DPB、DPC呢?
能给个从视频流中提取I frame 和P frame的方法么?
-----------------------------------------------------------------------------------------------
一个frame是可以分割成多个Slice来编码的,而一个Slice编码之后被打包进一个NAL单元,不过NAL单元除了容纳Slice编码的码流外,还可以容纳其他数据,比如序列参数集SPS
------------------------------------------------------------------------------------------------
// H.264 NAL type
enum H264NALTYPE
{
H264NT_NAL = 0,
H264NT_SLICE, //P 帧
H264NT_SLICE_DPA,
H264NT_SLICE_DPB,
H264NT_SLICE_DPC,
H264NT_SLICE_IDR, // I 帧
H264NT_SEI,
H264NT_SPS,
H264NT_PPS,
};
// 0x00 0x00 0x00 0x01 0x65(0x45) 前四个字节为帧头,0x65 是关键帧
//0x00 0x00 0x01 0x65(0x45) 也为关键帧
H264GetNALType(unsigned char * pBSBuf, const int nBSLen)
{
if ( nBSLen < 5 ) // 不完整的NAL单元
return H264NT_NAL;
unsigned char * pBS = (unsigned char *)pBSBuf;
int nType = pBS[4] & 0x1F; // NAL类型在固定的位置上
if ( nType <= H264NT_PPS )
return nType;// nTYPE 为5 表示关键帧
return 0;
}
------------------------------------------------------------------------------------------------
其中 H264NT_SLICE_IDR 是关键帧,H264NT_SLICE 是P帧
------------------------------------------------------------------------------------------------
一个frame是可以分割成多个Slice来编码的,而一个Slice编码之后被打包进一个NAL单元,不过NAL单元除了容纳Slice编码的码流外,还可以容纳其他数据,比如序列参数集SPS。
------------------------------------------------------------------------------------------------
1、NAL、Slice与frame意思及相互关系
NAL指网络提取层,里面放一些与网络相关的信息
Slice是片的意思,264中把图像分成一帧(frame)或两场(field),而帧又可以分成一个或几个片(Slilce);片由宏块(MB)组成。宏块是编码处理的基本单元。
2、NALnal_unit_type中的1(非IDR图像的编码条带)、2(编码条带数据分割块A)、3(编码条带数据分割块B)、4(编码条带数据分割块C)、5(IDR图像的编码条带)种类型
与 Slice种的三种编码模式:I_slice、P_slice、B_slice
NAL nal_unit_type 里的五种类型,代表接下来数据是表示啥信息的和具体如何分块。
I_slice、P_slice、B_slice表示I类型的片、P类型的片,B类型的片.其中I_slice为帧内预测模式编码;P_slice为单向预测编码或帧内模式;B_slice中为双向预测或帧内模式。
3、还有frame的3种类型:I frame、P frame、 Bframe之间有什么映射关系么?
I frame、P frame、 B frame关系同I_slice、P_slice、B_slice,slice和frame区别在问题1中已经讲明白。
4、最后,NALnal_unit_type中的6(SEI)、7(SPS)、8(PPS)属于什么帧呢?
NAL nal_unit_type为序列参数集(SPS)、图像参数集(PPS)、增强信息(SEI)不属于啥帧的概念。表示后面的数据信息为序列参数集(SPS)、图像参数集(PPS)、增强信息(SEI)。
h.264解码中首先过滤码流获得参数集,参数集是H.264标准的一个新概念,是一种通过改进视频码流结构增强错误恢复能力的方法。众所周知,一
些关键信息比特的丢失(如序列和图像的头信息)会造成解码的严重负面效应,而H.264把这些关键信息分离出来,凭借参数集的设计,确保在易出错的环境中
能正确地传输。这种码流结构的设计无疑增强了码流传输的错误恢复能力。
H.264的参数集又分为序列参数集(Sequence parameter
set)和图像参数集(Pictureparameterset)。其中,序列参数集包括一个图像序列的所有信息,即两个IDR图像间的所有图像信息。图
像参数集包括一个图像的所有分片的所有相关信息,包括图像类型、序列号等,解码时某些序列号的丢失可用来检验信息包的丢失与否。多个不同的序列和图像参数
集存储在解码器中,编码器依据每个编码分片的头部的存储位置来选择适当的参数集,图像参数集本身也包括使用的序列参数集参考信息。
参数集具体实现的方法也是多样化的:(1)通过带外传输,这种方式要求参数集通过可靠的协议,在首个片编码到达之前传输到解码器;(2)通过带内传
输,这需要为参数集提供更高级别的保护,例如发送复制包来保证至少有一个到达目标;(3)在编码器和解码器采用硬件处理参数集。
序列参数集以及图像参数集要在解码前传输,在解码的过程中被激活。一旦被激活,则上一个序列参数集或者图象参数集就失效了。图象参数集是被使用它的
slice
data或者使用它的A分割的Nalu激活的。而序列参数集是被使用它的图象参数集或者包括缓冲期消息的SEInalu所激活。同一个IDR图象的序列参
数集有相同的seq_parameter_set_id,直到一个图象的最后一个accessunit或者包括缓冲期消息的SEI
Nalu,这时需要出现下一个图象的序列参数集。下一个图象的序列参数集被SEInalu激活。如果序列参数集和图象参数集是通过其他传输管道发送的,则
要保证以上的传输顺序。
------------------------------------------------------------------------------------------------
H.264视频流是以NAL单元传送的。。。但在一个NAL单元里面,可能既存放I-Slice(P-Slice或B-Slice),同事也可能存放图像的其他信息
那么 是不是说 I frame, P frame,B frame是把收到的NAL单元中的VCL的信息先提取出,然后按内容进行I、P、Bframe分类?
而我们只能通过NAL nal_unit_type来判别NAL单元中数据的类型哈~~~
呵呵 不好意思 还没有完全理解~~
NAL单元中首先会有一个H.264 NAL type,根据这个可以判断是啥信息。如果是
H264NT_SLICE_DPA,H264NT_SLICE_DPB,H264NT_SLICE_DPC,H264NT_SLICE_IDR视频数据相
关的,里面还会有Slicehead头信息,根据这个头信息,可以判断属于I-Slice(P-Slice或B-Slice),之后对于每个宏块,都会有
MB head信息,根据宏块头信息可以判断块模式。
h264 Nalu 详解
http://blog.csdn.net/d_l_u_f/article/details/7260772
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单元以前发送,并且重复传送,大大提高纠错能力。序列和图像参数集可以在“带内”,也可以用更为可靠的其他“带外”通道传送。
存储单元:
一组指定格式的NAL单元称为存储单元,每个存储单元对应一个图像。每个存储单元包含一组VCL NAL单元,组成一个主编码图像,VCL NAL单元由表示视频图像采样的像条所组成。存储单元前面可以加一个前缀,分界存储单元,附加增强信息(SEI)(如图像定时信息)也可以放在主编码图像 的前面。主编码图像后附加的VCL NAL单元,包含同一图像的冗余表示,称为冗余编码图像,当主编码图像数据丢失或损坏时,可用冗余编码图像解码。
编码视频序列
一个编码视频序列由一串连续的存储单元组成,使用同一序列参数集。每个视频序列可独立解码。编码序列的开始是即时刷新存储单元(IDR)。IDR是一个I帧图像,表示后面的图像不用参考以前的图像。一个NAL单元流可包含一个或更多的编码视频序列。
RTP协议:
实时传输协议(Real-time Transport Protocol,RTP)是在Internet上处理多媒体数据流的一种网络协议,利用它能够在一对一(单播)或者一对多(multicast,多播) 的网络环境中实现传流媒体数据的实时传输。RTP通常使用UDP来进行多媒体数据的传输,但如果需要的话可以使用TCP或者ATM等其它协议,整个RTP 协议由两个密切相关的部分组成:RTP数据协议和RTP控制协议。实时流协议(Real Time Streaming Protocol, RTSP)最早由Real Networks和Netscape公司共同提出,它位于RTP和RTCP之上,其目的是希望通过IP网络有效地传输多媒体数据。
RTP数据协议
RTP数据协议负责对流媒体数据进行封包并实现媒体流的实时传输,每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前12个字节的含义是固定的,而负载则可以是音频或者视频数据。RTP数据报的头部格式如图1所示:
其中比较重要的几个域及其意义如下:
CSRC记数(CC) 表示CSRC标识的数目。CSRC标识紧跟在RTP固定头部之后,用来表示RTP数据报的来源,RTP协议允许在同一个会 话中存在多个数据源,它们可以通过RTP混合器合并为一个数据源。例如,可以产生一个CSRC列表来表示一个电话会议,该会议通过一个RTP混合器将所有 讲话者的语音数据组合为一个RTP数据源。
负载类型(PT) 标明RTP负载的格式,包括所采用的编码算法、采样频率、承载通道等。例如,类型2表明该RTP数据包中承载的是用ITU G.721算法编码的语音数据,采样频率为8000Hz,并且采用单声道。
序列号 用来为接收方提供探测数据丢失的方法,但如何处理丢失的数据则是应用程序自己的事情,RTP协议本身并不负责数据的重传。
时间戳 记录了负载中第一个字节的采样时间,接收方能够时间戳能够确定数据的到达是否受到了延迟抖动的影响,但具体如何来补偿延迟抖动则是应用程序自己的 事情。从RTP数据报的格式不难看出,它包含了传输媒体的类型、格式、序列号、时间戳以及是否有附加数据等信息,这些都为实时的流媒体传输提供了相应的基 础。RTP协议的目的是提供实时数据(如交互式的音频和视频)的端到端传输服务,因此在RTP中没有连接的概念,它可以建立在底层的面向连接或面向非连接 的传输协议之上;RTP也不依赖于特别的网络地址格式,而仅仅只需要底层传输协议支持组帧(Framing)和分段(Segmentation)就足够 了;另外RTP本身还不提供任何可靠性机制,这些都要由传输协议或者应用程序自己来保证。在典型的应用场合下,RTP一般是在传输协议之上作为应用程序的 一部分加以实现的,如图2所示:
RTCP控制协议
RTCP控制协议需要与RTP数据协议一起配合使用,当应用程序启动一个RTP会话时将同时占用两个端口,分别供RTP和RTCP使用。RTP本 身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完成。通常RTCP会采用与RTP相同的分发机制,向会话 中的所有成员周期性地发送控制信息,应用程序通过接收这些数据,从中获取会话参与者的相关资料,以及网络状况、分组丢失概率等反馈信息,从而能够对服务质 量进行控制或者对网络状况进行诊断。
RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:
SR 发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。
RR 接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。
SDES 源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。
BYE 通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。
APP 由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。
RTCP数据报携带有服务质量监控的必要信息,能够对服务质量进行动态的调整,并能够对网络拥塞进行有效的控制。由于RTCP数据报采用的是多播方式,因此会话中的所有成员都可以通过RTCP数据报返回的控制信息,来了解其他参与者的当前情况。
在一个典型的应用场合下,发送媒体流的应用程序将周期性地产生发送端报告SR,该RTCP数据报含有不同媒体流间的同步信息,以及已经发送的数据报 和字节的计数,接收端根据这些信息可以估计出实际的数据传输速率。另一方面,接收端会向所有已知的发送端发送接收端报告RR,该RTCP数据报含有已接收 数据报的最大序列号、丢失的数据报数目、延时抖动和时间戳等重要信息,发送端应用根据这些信息可以估计出往返时延,并且可以根据数据报丢失概率和时延抖动 情况动态调整发送速率,以改善网络拥塞状况,或者根据网络状况平滑地调整应用程序的服务质量。
RTSP实时流协议
作为一个应用层协议,RTSP提供了一个可供扩展的框架,它的意义在于使得实时流媒体数据的受控和点播变得可能。总的说来,RTSP是一个流媒体表 示协议,主要用来控制具有实时特性的数据发送,但它本身并不传输数据,而是必须依赖于下层传输协议所提供的某些服务。RTSP可以对流媒体提供诸如播放、 暂停、快进等操作,它负责定义具体的控制消息、操作方法、状态码等,此外还描述了与RTP间的交互操作。
RTSP在制定时较多地参考了HTTP/1.1协议,甚至许多描述与HTTP/1.1完全相同。RTSP之所以特意使用与HTTP/1.1类似的语 法和操作,在很大程度上是为了兼容现有的Web基础结构,正因如此,HTTP/1.1的扩展机制大都可以直接引入到RTSP中。
由RTSP控制的媒体流集合可以用表示描述(Presentation Description)来定义,所谓表示是指流媒体服务器提供给客户机的一个或者多个媒体流的集合,而表示描述则包含了一个表示中各个媒体流的相关信 息,如数据编码/解码算法、网络地址、媒体流的内容等。
虽然RTSP服务器同样也使用标识符来区别每一流连接会话(Session),但RTSP连接并没有被绑定到传输层连接(如TCP等),也就是说在 整个RTSP连接期间,RTSP用户可打开或者关闭多个对RTSP服务器的可靠传输连接以发出RTSP 请求。此外,RTSP连接也可以基于面向无连接的传输协议(如UDP等)。
RTSP协议目前支持以下操作:
检索媒体 允许用户通过HTTP或者其它方法向媒体服务器提交一个表示描述。如表示是组播的,则表示描述就包含用于该媒体流的组播地址和端口号;如果表示是单播的, 为了安全在表示描述中应该只提供目的地址。
邀请加入 媒体服务器可以被邀请参加正在进行的会议,或者在表示中回放媒体,或者在表示中录制全部媒体或其子集,非常适合于分布式教学。
添加媒体 通知用户新加入的可利用媒体流,这对现场讲座来讲显得尤其有用。与HTTP/1.1类似,RTSP请求也可以交由代理、通道或者缓存来进行处理。
3. JM86中的处理
涉及的函数:
流程图:
I帧和IDR帧的区别:
1. 在 H.264 中 I 帧并不具有随机访问的能力,这个功能由 IDR 承担。以前的标准中由 I 帧承担。
2. IDR 会导致 DPB (参考帧列表——这是关键所在)清空,而 I 不会。
3. I和IDR帧其实都是I帧,都是使用帧内预测的。但是IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始,重新算一个新的序列开始编码。
4. IDR图像一定是I图像,但I图像不一定是IDR图像。一个序列中可以有很多的I图像,I图像之后的图像可以引用I图像之间的图像做运动参考。