1
朱晓蓉 南京铁道职业技术学院 |
摘 要:本文主要介绍H.264标准中的分层技术:视频编码麈(VCL:Video Coding Layer): ‘网络提取层(NAL:Network Abstraction Layer)。 关键词:H.264标准分层技术 视频编码层网络提取层 |
H.264的算法在概念上可以分为两层:视频编码层(VCL:Video Coding Layer)负责高效的视频 内容表示,网络提取层(NAL:Network Abstraction Layer)负责以网络所要求的恰当的方式对数据 进行打包和传送。 1. NAL层 NAL层的设计主要是为了提供“友好网络”,使得VCL层中内容能够简单而有效应用于各种各样的 系统中。NAL层可把VCL层的数据封装成以下传输层: ·为各种实时的有线和无线网络服务的RTP/TP协议 ·文件格式如ISO MP4存贮格式和MMS格式 ·为有线和无线会话服务的H32X协议 ·为广播服务的MPEG-2系统 (1)NAL单元的定义 NAL层是由NAL单元(NAL unit)所构成。每个NAL单元第一个字节是头信息,说明NAL单元的数 据类型。接下来是负载数据,它包含整数个编码的图像数据字节。在负载中也有可能包含仿效阻止字 节(emulation prevention bytes),用来避免负载数据中包含有起始码前缀(start code prefix)。 在标准中定义了两种传输NAL单元结构的流格式,分别为面向数据包的传输格式和面向比特流的 传输格式。在比特流格式中,每个NAL单元都是由称为起始码前缀(start code prefix)的三个字节 流(Ox000001)开始。为了在NAL单元中只有一个唯一起始码前缀,负载数据中如果包含有此二个字 节就在第三个字节前插入仿效阻止字节(Ox03)。这样可把起始码前缀作为对NAL单元的唯一标识。在 每个NAL单元最后字节也许包含附加数据,用于负载数据字节同步。具体阐述可见标准中附录B(包含 有NAL单元语法和解码过程)。在数据包格式中,编码的图像数据将被封装到传输协议(如RTP)包中, 在此数据包中将不包含起始码前缀。NAL层定义在标准中的语法为表1。 |
传送NAL单元流分类代码在main()函数中是利用switch—case结构来实现的。其中在input一>FileFormat结构中存放着用户对文档格式设置的参数,当为O时表示比特流的格式,为1时为RTP数据包格式。input->infile表示需要打开的视频文件。当文件格式为比特流时,其NAL单元中就应包含了起始码前缀(start code prefix)并作为与其他NAL单元相区别唯一标识。其在标准附录B中的语法为表2。
在实际应用中代码首先是找起始码前缀三个字节(Ox000001),由上边语法可知也许在此三个字节 前可能有许多个0字节,必须先要剔除了。然后再找下一个起始码前缀,此时整个NAL单元就应为第二个起始码前缀前面字节到前一个起始码前缀后面字节之间的字节数。接着读取NAL单元第一个字节,具体语法可见上面NAL定义语法。操作是在函数GetAnnexbNALU中。其程序框图如图l: |
(2) NAL单元的分类
NAL单元可分为VCL单元和非VCL单元。VCL单元中包含着图像数据的抽样值。非VCL单元包含着与图像数据相关的附加信息,如参数设置信息(作为图像解码的头信息)和增强信息(时间信息等)。参数设置信息作为VCL单元解码的信息。它包括两种参数设置:(1)序列参数设置信息(2)图像参数设置信息。对于每个VCL单元都对应有这两种参数设置。参数设置信息能够提供强大纠错能力,阻止数据的流失。在某些应用中参数设置信息可以和传输VCL单元信息公用一个信道(称为“带内”传输),在另一些应用中,如图2参数设置信息可利用比传输VCL单元信息更可靠的“带外”信道进行传输。在
标准中根据NAL单元第一字节中nal_unit_type,把NAL单元又进行具体细分。 |
图2 NAL单元 |
其中nal_unit_type为O和13~31不作说明,1~5类型的NAL单元为VCL单元,6~10类型的NAL 单元为非VCL单元。 它在JM-7.5b中用了switch—case结构实现的,代码为: switch(nalu->nal_unit_type) { case NALU_TYPE_SLICE: case NALU_TYPE-IDR: (略) case NALU_TYPE_DPA: (略) |
case NALUJYPE_DPB: (略) case NALUJYPE_DPC: (略) case NALU_TYPE_SEI: case NALU_TYPE_PPS: ProcessPPS(nalu)://获取图像参数设置信息给pps结构,并保存在PicParSet[id] break: case NALU_TYPE_SPS: ProcessSPS(nalu)://获取序列参数设置信息给sps结构,并保存在SeqParSet[id] |
break:
case NALU—TYPE_PD: (略) |
case NALU TYPE—EOSEQ: (略) |
case NALUJYPE_EOSTREAM: (略) |
case NALU_TYPE_FILL: (毋各) default: |
printf(”Found NALU type%d, len%d undefined, ignore NALU,moving on\n”, |
nalu一>nal_unit_type , nalu->len): |
这段代码是在函数read_new_slice()中。 |
NAL单元典型码见表3。 |
66
1
(3)NAL单元的结构 从上面对NAL单元的语法分析可知,NAL单元除了第一字节说明本单元的属性外,还有就是负载部 分,它在标准中是以RBSP数据结构封装着。而RBSP结构中又包含SODB数据结构,它与RBSP结构区 别为: ①如果SODB结构中数据为0字节,RBSP结构也将不存在。 ②否则,在RBSP结构中,紧接在SODB后一个比特,在标准中称为rbsp_stop_one_bit等于1。然 后加O使得字节对齐。图3画出NAL单元结构框图: NAL单元 |
|
图3 NAL单元结构框图 |
对于在JM一7.5b中从RBSP数据结构中获取SODB结构的代码为: int RBSPtoSODB(byte*streamBuffer,int last_byte_pos) { int ctr_bit,bitoffset: ’ bitoffset=O: //发现rbsp_stop_one_bit(1) ctr_bit=(streamBuffer[1ast_byte_pos一1]&(OxOl<<bitoffset)): while(ctr_bit==0) { bitoffset++: if(bitoffset==8) { if(1ast_byte_pos==0) printf(”Panic:A11 zero data sequence in RBSP\n”): assert(1ast_byte_pos!=O): last_byte_pos一=1: bitoffset=0: ) |
ctr bit。streamBuffer[1ast_byte_pos-1]&(0xOl<<(bitoffset)): ) |
函数参数last_byte pos为NAL单元字节数减去第一个字节,streambuffer为存放NAL单元内容 的第2字节的地址。 |
2. NAL单元流的结构 在NAL单元流中可能包含有一个或一个已编码好的图像序列,每个序列是由一系列的接入单元 (Access Units),它们使用同样序列参数设置信息,能够独立于其他序列进行解码。 |
开始 |
元所组成,其中包含图像抽样值条或条数据分片信息。随后冗余编码图像信息(redundant coded
77
结束 接入单元的结构 图4接入单元结构 |
每个接入单元组成可见下图4,它由一组NAL单元所形成,其包含一幅图像的信息,解码后可构成 一幅图像。由图可知在接入单元可包含接入单元定界符(access unit del imiter)帮助确定接入单元 的开始,也可包含辅助增强信息如时间信息。这里主编码图像(primary coded picture)是由VCL单 |
picture)包含与主编码图像信息一样的图像内容,主要用于数据的丢失或衰变后恢复,在解码中不作 要求。最后,如果当前接入单元(图像)是图像序列中最后一帧图像,就在本接入单元中加入序列尾 (end of sequence)。如果当前接入单元(图像)是整个NAL单元流中最后一幅图像,则在本接入单 元后还需加入传输流尾(end of stream)。在每个编码图像序列开始第一接入单元总是IDR (instantaneous decoding refresh)接入单元。这种接入单元(图像)属于帧内编码图像,不需要 其他图像作为参考图像就可以解码。对于编码图像序列结构参见框图5。 |
非vcL单元 非vcL单元 非vcL单元 非VcL单元 |
E-mai 1:summerOlOl@126.com 南京铁道职业技术学院通信工程系 邮政编码:210015 13851557305 |
|
接入单元 图像序列的结构囝 |
图5图像序列结构 |