基于H.264的RTP打包原理和FU-A分片实例分析

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/freeyond/article/details/77918253

1. H.264码流结构

  H.264编码规范从逻辑上划分为视频编码层(VCL)和网络提取层(NAL)。
  VCL数据是由编码器直接输出的原始数据比特串(SODB),它表示图像被压缩后的编码比特流。
  VCL数据要在网络上传输或者存储到磁盘上之前,需要先被封装或映射进NAL单元(NALU)中,每个NAL单元之前需要添加StartCodePrefix,最后形成H.264码流,H.264码流结构如图1-1所示(annex-b byte stream format,详见H.264建议书附录B部分)。
这里写图片描述

图1-1 H.264码流结构

  关于H.264码流结构的详细内容可以参考我的另一篇文章:
  《H.264码流格式

2. NALU结构

  H.264码流由NALU序列组成,通过RTP协议封装和传输H.264码流实际上就是对H.264序列中NALU的封装和传输。在介绍RTP打包封装H.264码流之前,我们先来简单了解NALU的结构。
  NAL单元(NAL Unit,简称NALU)由1个NAL头(NAL Header)和1个RBSP(或EBSP)组成。
  NAL头(NAL Header)长度为1个字节,由“forbidden_zero_bit”、“nal_ref_idc”和“nal_unit_type”三个字段组成。NAL Header结构如果图2-1所示:
这里写图片描述

图2-1 NAL Header结构

  F:forbidden_zero_bit,1位,初始为0,当NAL单元在网络传输过程中识别为错误时,可设置该字段为 1,以便接收方纠错或丢掉该单元。
  NRI:nal_ref_idc,2 位,用来指示该NALU 的重要性等级。值越大,越重要,解码器在解码处理不过来的时候,可以丢掉重要性为0的NALU。
  TYPE:nal_unit_type ,5 位,指出NALU 的类型。
nal_unit_type 是指包含在NALU中的 RBSP 数据结构的类型,取值如下图所示:
这里写图片描述
图 2-2 nal_unit_type

  nal_unit_type的值在1到5之间的NALU称为VCL NALU,其余的称为非VCL NALU。
  通过图2-2可以看到,nal_unit_type的取值除了H.264编码占用了一部分以外(取值为0~23),剩下的一部分(取值为24~31)在RTP打包时会使用。

3. RTP打包模式

3.1 RTP包结构

  RTP包由rtp header和rtp payload组成,RTP包结构如图3-1所示:
这里写图片描述

图 3-1 RTP包结构

  使用RTP打包H.264码流时,定义了三个不同的载荷结构:单一NAL单元包、组合包和分片单元。
  接收者可以通过payload的第一个字节识别载荷结构,我们称它为payload header。
  payload header总是被格式化为NALU header,也就是说它和NALU header的结构一致,各字段具有相同意义。
  payload header的TYPE字段用于描述payload中NALU的类型,通过图2-2可以看到,RTP打包时使用了24~31之间的TYPE值。
  图3-2描述了payload中NALU类型和载荷结构分类。
这里写图片描述
图 3-2 NALU类型和载荷结构

3.2 载荷结构

  载荷结构分为单个NAL单元包、组合包和分片单元三种类型。
  需要注意的是载荷结构并不等同于打包模式,它只是打包模式的子集,每个打包模式都支持若干个载荷结构,我们将在下一节描述每种打包模式支持的载荷结构。

3.2.1 单个NAL单元包

  单个NAL单元包是指,H.264码流(NALU序列)中的每个NALU都独立封装成一个RTP包,不拆分,不组合。
  单个NAL单元包的打包示意图如下:
这里写图片描述

图 3-3 单个NAL单元包

  单个NAL单元包必须只包含TYPE为1~23的NAL单元。这意味着组合包和分片单元不可以用在单个NAL单元包中。一个封装单个NAL单元包到RTP的NAL单元流的RTP序号必须符合NAL单元的解码顺序。单个NAL单元包的结构如图3-4所示。
这里写图片描述
图 3-4 单个NAL单元包结构

3.2.2 组合包

  组合包是指,H.264码流(NALU序列)中有若干NALU尺寸特别小,因此可以将多个NALU进行组合后封装进一个RTP包。
  组合包的打包示意图如下:
这里写图片描述

图 3-5 组合包

3.2.3 分片单元(FUs)

  分片单元是指,H.264码流(NALU序列)中NALU长度超过MTU大小限制,因此需要将这样的NALU进行分片。
  FU-A分片单元的打包示意图如下:
这里写图片描述

图 3-6 FU-A分片单元

  分片只定义于单个NAL单元不用于任何组合包。NAL单元的一个分片由整数个连续NAL单元字节组成。每个NAL单元字节必须正好是该NAL单元一个分片的一部分。相同NAL单元的分片必须使用递增的RTP序号连续顺序发送(第一和最后分片之间没有其他的RTP包)。相似,NAL单元必须按照RTP顺序号的顺序装配。
  当一个NAL单元被分片运送在分片单元(FUs)中时,被引用为分片NAL单元。 STAPs,MTAP不可以被分片。FUs不可以嵌套。即,一个FU 不可以包含另一个FU。
  运送FU的RTP时戳被设置成被分片NALU的时戳。
  图3-7表示FU-A的RTP荷载格式。 FU-A由1字节的分片单元指示(FU indicator),1字节的分片单元头(FU Header),和分片单元荷载(FU payload)组成。
这里写图片描述
图 3-7 FU-A分片结构

  FU indicator结构如下:
这里写图片描述
图 3-8 FU indicator结构

  FU indicator结构和payload header结构一致,TYPE为28代表FU-A分片,TYPE为29代表FU-B分片。
  Fu header结构如下:
这里写图片描述
图 3-9 FU header结构

  S:1 bit,开始位
  当设置成1,开始位指示分片NAL单元的开始。当跟随的FU荷载不是分片NAL单元荷载的开始,开始位设为0。
  E:1 bit,结束位
  当设置成1, 结束位指示分片NAL单元的结束,即, 荷载的最后字节也是分片NAL单元的最后一个字节。当跟随的FU荷载不是分片NAL单元的最后分片,结束位设置为0。
  R:1 bit,保留位
  保留位必须设置为0,接收者必须忽略该位。
  TYPE:5 bit,NALU类型
  与被分片的NALU类型一致。

3.3 打包模式

  基于H.264码流的RTP打包模式分为三种:
  (1)单NAL单元模式
  (2)非交错模式
  (3)交错模式
  图3-10总结了每种打包模式支持的NALU类型:
这里写图片描述

图 3-10 打包模式支持的NALU类型

4. 非交错打包模式组帧实例分析

  抓包实例文件下载地址:
  FU-A分片实例.7z
  文件“FU-A分片实例.7z”中包含两个文件:
  (1) FUA_SLICE.pcap,抓取的一段基于H.264码流的RTP包,打包模式为非交错模式,包含两种载荷结构:单个NAL单元包和FU-A分片单元。
  (2) frame.bin,从抓包文件中组出一个完整的IDR帧,包括SPS、PPS、SEI和4个IDR_SLICE。
  FUA_SLICE.pcap中一个完整的IDR帧包括序列号从23861到23896的RTP包,组帧示意图如下:
这里写图片描述

图 4-1 IDR组帧

  从图4-1可以看出,一个IDR帧包括了4个IDR_SLICE,每个IDR_SLICE都是完整图像的一部分,可以被独立解码。
  frame.bin中包含的就是从RTP包序列号23861到23896组装的完整IDR帧,其NALU序列为:SPS+PPS+SEI+SEI+IDR_SLICE(0)+ IDR_SLICE(1)+ IDR_SLICE(2)+ IDR_SLICE(3),如果4-2所示:
这里写图片描述
图 4-2 NALU序列

展开阅读全文

流媒体,H.264,RTP,FU-A,解码播放

10-26

开发某实时视频浏览程序,使用RTSP握手后,设备向PC指定UDP端口回传FU-A封包的H.264视频数据,不知道如何进行解码。rn交互过程如下(P:PC, D:设备):rnP -> D:rnDESCRIBE rtsp://192.168.0.13:554/h264.sdp?res=full&x0=0&y0=0&x1=352&y1=288 RTSP/1.0rnAccept: application/sdprnAuthorization: Basic YWRtaW46ODg4ODg4ODg=rnUser-Agent: H264TestClientrnCSeq: 1rnrnD -> P:rnRTSP/1.0 200 OKrnCSeq: 1rnCache-Control: no-cachernContent-Length: 234rnContent-Type: application/sdprnx-Accept-Retransmit: our-retransmitrnx-Accept-Dynamic-Rate: 1rnrnv=0rno=channel0 37541 33321 IN IP4 192.168.0.13rns=h264.sdprnt=0 0rnm=video 0 RTP/AVP 96rna=rtpmap:96 H264/90000rna=control:trackID=1rna=fmtp:96 packetization-mode=1;profile-level-id=428032;sprop-parameter-sets=Z0KAMukCgSyA,aM48gA==rnrnP -> D:rnSETUP rtsp://192.168.0.13:554/h264.sdp?res=full&x0=0&y0=0&x1=352&y1=288 RTSP/1.0rnTransport: RTP/AVP/TCP;unicast;client_port=10000-10001;ssrc=0rnUser-Agent: H264TestClientrnCSeq: 2rnrnD -> P:rnRTSP/1.0 200 OKrnCSeq: 2rnCache-Control: no-cachernSession: 135514808124572rnTransport: RTP/AVP;unicast;client_port=10000-10001;server_port=6970-6971rnrnP -> D:rnPLAY rtsp://192.168.0.13:554/h264.sdp?res=full&x0=0&y0=0&x1=352&y1=288 RTSP/1.0rnSession: 135514808124572rnRange: npt=0.000000-0.000000rnUser-Agent: H264TestClientrnCSeq: 3rnrnD -> P:rnRTSP/1.0 200 OKrnCSeq: 3rnSession: 135514808124572rnRange: npt=now-rnrnrn至此rtsp握手成功,设备开始用UDP回传数据,每一个UDP包都是一个FU-A包(首12字节是RTP包头),如:rnpacket 1, length = 1472:rn80 60 00 01 7A FD 74 05 rn4B 0B B9 BE 7C 85 88 80 rn15 40 34 23 14 00 04 52 rnF5 26 E4 E4 E4 E4 E4 E4 rn........rnrnpacket 2, length = 1472:rn80 60 00 02 7A FD 74 05 rn4B 0B B9 BE 7C 05 B2 A8 rn3F 0B 0A 2F F4 FE DE 17 rnC0 04 8A 1A 15 46 80 95rn....rn....rnrnpacket 5, length = 500:rn80 E0 00 05 7A FD 74 05 rn4B 0B B9 BE 7C 45 F5 AF rnF4 47 EA C1 4E 80 8C 3B rn3C EE 93 08 94 81 EE 09 rn....rnrn用VLC是可以直接连接并播放的。rn目前问题是提取FU-A的payload后不知道应当如何进行播放,盼高手赐教。rn 论坛

没有更多推荐了,返回首页