ANNEXB格式.docx
- 文档编号:12632750
- 上传时间:2023-04-21
- 格式:DOCX
- 页数:11
- 大小:57.19KB
ANNEXB格式.docx
《ANNEXB格式.docx》由会员分享,可在线阅读,更多相关《ANNEXB格式.docx(11页珍藏版)》请在冰豆网上搜索。
ANNEXB格式
AnnexB格式:
NALU数据+开始前缀(00000001或000001,此处注意为甚么是4bit或3bit,后面有描述);针对H.320电话会议
RTP格式:
NALU数据+20个字节的类似的并不符合RTP协议的RTP头。
针对IP网络的RTP打包方式
H.264协议只规定了字节流格式,没有规定RTP格式。
可能也是因为这个原因,JM的RTP格式没有被用到任何场合场合中,成为了摆设。
下图中的RTP格式是h.264乐园的firstime从JM86中分析出来的。
实际包交换网络中必须按照RFC3984将NALU数据封装为RTP包,而不能使用JM的RTP格式。
下面引自“QUESTIONMARK”的博客
下面说明3字节起始码和4字节起始码。
以下和leading_zero_8bits、trailing_zero_8bits已无关系,忘掉。
if(next_bits(24)!
=0x000001)
zero_bytef(8)
start_code_prefix_one_3bytesf(24)
根据B.1节,可以看到所谓的4字节起始码是(zero_byte+3字节起始码)。
那么看zero_byte的说明,就可以明白zero_byte什么时候出现,也就能明白什么时候出现4字节起始码:
1.SPS、PPSnalu是4字节起始码;
2.AccessUnit的首个nalu是4字节起始码(参见7.4.1.2.3)。
这里举个例子说明,用JM可以生成这样一段码流(不要使用JM8.6,它在这部分与标准不符),这个码流可以见本楼附件:
SPS(4字节头)
PPS(4字节头)
SEI(4字节头)
I0(slice0)(4字节头)
I0(slice1)(3字节头)
P1(slice0)(4字节头)
P1(slice1)(3字节头)
P2(slice0)(4字节头)
P2(slice1)(3字节头)
I0(slice0)是序列第一帧(I帧)的第一个slice,是当前AccessUnit的首个nalu,所以是4字节头。
而I0(slice1)表示第一帧的第二个slice,所以是3字节头。
P1(slice0)、P1(slice1)同理。
总结:
1附录B字节流在一个byte_stream_nal_unit的前后可能出现若干个0x00,仅用作填充之用。
这个不常见。
24字节头只出现在SPS、PPS和7.4.1.2.3规定的AccessUnit的首个nalu。
其余情况都是3字节头
一共有两种起始码:
3字节的0x000001和4字节的0x00000001
3字节的0x000001只有一种场合下使用,就是一个完整的帧被编为多个slice的时候,包含这些slice的nalu使用3字节起始码。
其余场合都是4字节的。
NAL层处理简析
(2010-06-0916:
00:
34)
转载▼
标签:
nal层
nal
杂谈
分类:
H.264
NAL(NetworkAbstractionLayer)基本上可分两种:
1,以有序字节流方式传送的针对H.320的;2,针对IP网络的RTP打包方式的。
NAL作用:
specifiedtoformatthatdataandprovideheaderinformationinamannerappropriateforconveyanceonavarietyofcommunicationchannelsorstoragemedia.
NAL的处理过程基本上分为两步:
1,将VCL层输出的SODB封装成nal_unit.
Nal_unit是一个通用封装格式,可以适用于有序字节流方式和IP包交换方式。
2,针对不同的传送网络(电路交换|包交换),将nal_unit封装成针对不同网络的封装格式。
第一步的具体过程:
VCL层输出的比特流SODB(StringOfDataBits),到nal_unit之间,经过了以下三步处理:
1,SODB字节对齐处理后封装成RBSP(RawByteSequencePayload)。
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 if(i+2 rbsp_byte[NumBytesInRBSP++] rbsp_byte[NumBytesInRBSP++] i+=2 emulation_prevention_three_byte }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 if(more_data_in_byte_stream()){ start_code_prefix_one_3bytesnal_unit(NumBytesInNALunit) } } Case2: IP网络的RTP打包封装 IDR(刷新帧)与I帧的一些知识点 (2010-06-0820: 38: 40) 转载▼ 标签: 杂谈 分类: H.264 IDR帧属于I帧,但是I帧不一定是IDR帧。 解码器收到IDR帧时,将驱动器参数块(DPB)清空。 而I帧不会。 (我自己理解为即把参考帧列表刷新从新更新,就是不再参考idr前面的帧)由此可见,在编码器端,每发一个IDR,就相应地发一个nal。 当然在现在的编码中,为了取得更高的图像质量,在一个视频文件中有好多个IDR帧,这些IDR帧把视频文件分成了片,但是每片中第一个帧是IDR,而且仅此一个 例如: 存在这样一段视频: 码流 IDR B B P B B P …… 帧号 1 2 3 4 5 6 7 …… 对IDR帧的处理(与I帧的处理相同): (1)进行帧内预测,决定所采用的帧内预测模式。 (2)像素值减去预测值,得到残差。 (3)对残差进行变换和量化。 (4)变长编码和算术编码。 (5)重构图像并滤波,得到的图像作为其它帧的参考帧。 这里要提一下,当编码器处理完IDR帧遇到B帧时,编码期先把其放入缓存器中存放起来。 直接对P进行编码。 即编码器中编码的实际顺序是IDRPBBPBB…..即1423756…… 有用的来了 IDR-instantaneousdecodingrefresh(IDR)picture; AcodedpictureinwhichallslicesareIorSIslicesthatcausesthedecodingprocesstomarkallreferencepicturesas"unusedforreference"immediatelyafterdecodingtheIDRpicture.AfterthedecodingofanIDRpictureallfollowingcodedpicturesindecodingordercanbedecodedwithoutinterpredictionfromanypicturedecodedpriortotheIDRpicture.ThefirstpictureofeachcodedvideosequenceisanIDRpicture. “也就是说,IDR的出现其实是相当于向解码器发出了一个清理referencebuffer的信号吧,上面说前于这一帧的所有已编码帧不能为inter做参考帧了。 ” 还有: “因为264采用了多帧预测,就有可能在displayorder下I帧后的P会参考I帧前的帧,这样在randomaccess时如果只找I帧,随后的帧的参考帧可能unavailable,IDR就是这样一种特殊的I帧,把它定义为确保后面的P一定不参考其前面的帧,可以放心地randomaccess。 ” 多参考帧情况下。 【转】SODBRBSPEBSP的来龙去脉 (2010-06-0721: 22: 39) 转载▼ 标签: h.264 起始码 起始码竞争 数据流结构 杂谈 分类: H.264 H.264起始码 在网络传输h264数据时,一个UDP包就是一个NALU,解码器可以很方便的检测出NAL分界和解码。 但是如果编码数据存储为一个文件,原来的解码器将无法从数据流中分别出每个NAL的起始位置和终止位置,为此h.264用起始码来解决这一问题。 H.264编码时,在每个NAL前添加起始码0x000001,解码器在码流中检测到起始码,当前NAL结束。 为了防止NAL内部出现0x000001的数据,h.264又提出'防止竞争emulationprevention"机制,在编码完一个NAL时,如果检测出有连续两个0x00字节,就在后面插入一个0x03。 当解码器在NAL内部检测到0x000003的数据,就把0x03抛弃,恢复原始数据。 0x000000>>>>>>0x00000300 0x000001>>>>>>0x00000301 0x000002>>>>>>0x00000302 0x000003>>>>>>0x00000303 附上h.264解码nalu中检测起始码的算法流程 for(;;) { ifnext24bitsare0x000001 { startCodeFound=true break; } else { flush8bits } }//for(;;) if(true==startCodeFound) { //startcodefound //Flushthestartcodefound flush24bits //Nownavigateuptonextstartcodeandputtheinbetweenstuff //inthenalstructure. for(;;) { getnext24bits&checkifitequalsto0x000001 if(false==(next24bits==000001)) { //searchforpattern0x000000 checkifnext24bitsare0x000000 if(false==result) { //copythebyteintothebuffer copyonebytetotheNalunit } else { break; } } else { break; } }//for(;;) } 2.MPEG4起始码 MPEG4的特色是VOP,没有NALU的概念,仍使用startcode对每帧进行分界。 MPEG4的起始码是0x000001.另外MPEG4中很多起始码也很有用,比如video_object_sequence_start_code0x000001B0表示一个视频对象序列的开始,VO_start_code0x000001B6表示一个VOP的开始.0x000001B6之后的两位,是00表示Iframe,01表示Pframe,10表示Bframe. SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSPtrailingbits 一个bit“1”)若干比特“0”,以便字节对齐。 EBSP 扩展字节序列载荷-->在RBSP基础上填加了仿校验字节(0X03)它的原因是: 在NALU加到Annexb上时,需要填加每组NALU之前的开始码StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示ox000001.为了使NALU主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。 解码时将0x03去掉。 也称为脱壳操作。 网上查询的区别: 在对整帧图像的数据比特串(SODB)添加原始字节序列载荷(RBSP)结尾比特(RBSPtrailingbits,添加一比特的“1”和若干比特“0”,以便字节对齐)后,再检查RBSP中是否存在连续的三字节“0000000000000000000000xx”;若存在这种连续的三字节码,在第三字节前插入一字节的“0×03”,以免与起始码竞争,形成EBSP码流,这需要将近两倍的整帧图像码流大小。 为了减小存储器需求,在每个宏块编码结束后即检查该宏块SODB中的起始码竞争问题,并保留SODB最后两字节的零字节个数,以便与下一宏块的SODB的开始字节形成连续的起始码竞争检测;对一帧图像的最后一个宏块,先添加结尾停止比特,再检测起始码竞争。 本文来自CSDN博客,转载请标明出处: typedefstruct { intbyte_pos;//! intbits_to_go;//! bytebyte_buf;//! intstored_byte_pos;//! intstored_bits_to_go;//! bytestored_byte_buf;//! bytebyte_buf_skip;//! intbyte_pos_skip;//! intbits_to_go_skip;//! byte*streamBuffer;//! intwrite_flag;//! }Bitstream; 定义比特流结构 staticbyte*NAL_Payload_buffer; voidSODBtoRBSP(Bitstream*currStream) { currStream->byte_buf<<=1; //左移1bit currStream->byte_buf|=1; //在尾部填一个“1”占1bit currStream->bits_to_go--; currStream->byte_buf<<=currStream->bits_to_go; currStream->streamBuffer[currStream->byte_pos++]=currStream->byte_buf; currStream->bits_to_go=8; currStream->byte_buf=0; } intRBSPtoEBSP(byte*streamBuffer,intbegin_bytepos,intend_bytepos,intmin_num_bytes) { inti,j,count; for(i=begin_bytepos;i NAL_Payload_buffer[i]=streamBuffer[i]; count=0; j=begin_bytepos; for(i=begin_bytepos;i { if(count==ZEROBYTES_SHORTSTARTCODE&&! (NAL_Payload_buffer[i]&0xFC)) { streamBuffer[j]=0x03; j++; count=0; } streamBuffer[j]=NAL_Payload_buffer[i]; if(NAL_Payload_buffer[i]==0x00) count++; else count=0; j++; } while(j streamBuffer[j]=0x00;//cabacstuffingword streamBuffer[j+1]=0x00; streamBuffer[j+2]=0x03; j+=3; stat->bit_use_stuffingBits[img->type]+=16; } returnj; } 在2010-6-915: 33: 33我又看到了别人博客上的一句话更加深了我的理解,这里贴出来。 感谢QuestionMark 标准7.4.1.1如是说: ThisprocesscanallowanySODBtoberepresentedinaNALunitwhileensuringthat –…… –nosequenceof8zero-valuedbitsfollowedbyastartcodeprefix,regardlessofbyte-alignment,isemulatedwithintheNALunit. 这段的意思是在nal_unit层面,即naluheader+RBSP的结构中,不可能出现0x000001这样的片段。 这是通过SODB->RBSP->EBSP的过程中添加防冲突字节实现的。 这里多说一句 标准附录B如是说: anybytesequalto0x00thatfollowaNALunitsyntaxstructureandprecedethefour-bytesequence0x00000001(whichistobeinterpretedasazero_bytefollowedbyastart_code_prefix_one_3bytes)willbeconsideredtobetrailing_zero_8bitssyntaxelementsthatarepartoftheprecedingbytestreamNALunit. 这一段则在说明byte_stream_nal_unit层面。 结合B.1,可以明白这段话的意思是一个nalu之后,下一个起始码0x00000001之前,可能会有若干0x00,就是所谓的trailing_zero_8bits。 此外B.1中还说明了在码流的最开始,还有可能有若干0x00,就是所谓的leading_zero_8bits。 这些leading_zero_8bits和trailing_zero_8bits可能与传输打包有关,但在实际中,我没有见过包含这种“多余”的0x00的码流。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ANNEXB 格式