H264 over RTP 的解包


前一版博文《H264 over RTP 的打包》已经详细介绍了发送端如何将H264视频帧打包到RTP进行传输,现在我们书接上文,介绍接收端收到RTP包后如何解包组装还原出来H264帧。从前文我们知道发送端发送一帧H264数据时会遍历H264帧逐个将NALU打包成RTP包(当然NALU大于MTU时会进行分片),每一帧数据对应的RTP包的时间戳都是相同的,最后一个RTP包的marked位为TRUE;因此接收到只需要将接收到的RTP包组装成NALU,然后将NALU连接起来就可以还原H264帧了,由于网络传输可能会丢包和乱序,所以接收端还要有RTP接收缓存,用于RTP包排序(根据RTP头的SN进行排序)。

一帧H264打包为RTP包的示意图,一帧H264的所有RTP包时间戳相同,SN连续

一个H264帧由一些列NALU构成,每个NALU又被拆解(依据传输层的MTU去拆解)为若干个数据段,这些数据段打上一个头后(这个头部有NALU分段的标识,start_bit和end_bit表示起始数据段和结束数据段),再封装成rtp包去发送。传输同一个H264帧的rtp包都具有相同的时间戳。

rtp_j1为第j个NALU的起始数据段,其分段标识有start_bit=1;

rtp_jk为第j个NALU的结束数据段,其分段标识有end_bit=1;

在起始数据段和结束数据段之间的其它数据段由rtp的SN标识其先后顺序;

接收端可以根据收到rtp包的SN的连续性、以及start_bit和end_bit标志位来组成一个完整的NALU,以及判断一个NALU是否有丢包。

  • 接收Buffer设计

接收端采用双缓存机制,一个RTP缓存,用于RTP包的排序,一个帧缓存,用于存放组装出来的H264帧,解码和播放线程从帧缓存取数据。

RTP接收缓存的设计如下图所示,

RTP接收BUFFER,每个时间戳ti节点链表对应一个H264帧

缓存设计为二维的结构,横向是按照RTP包的时间排序,纵向按照rtp的SN排序,由于一个H264帧在发送端发送时其承载的所有rtp包都具有相同的时间戳,不同的H264帧其传输的rtp时间戳不一样,所以上图中某个时间节点下的所有rtp包属于同一个H264帧。

比如时间节点ti ,那么其对应的所有rtp包rtp_i1、rtp_i2、…、rtp_ik都是属于H264帧Frame_i的;其中,i=1、2、…、n,   k=1、2、…。

RTP的接收缓存大小为RTP_BUFFER_SIZE帧,如果接收buffer已满时收到新帧的RTP包,则对头节点出队列,强制将这个不完整的节点数据组成H264帧或者丢弃,这可取决于用户的配置。

帧缓存就是一个简单的链表,如下所示,

帧缓存里存放的是一个个完整的H264帧,播放线程会按照媒体协商的帧率(比如25帧/秒)的速率进行播放。

帧缓存的大小为FRAME_BUFFER_SIZE,如果接收到新帧时缓存已经满了,则从队头开始寻找一个P丢弃,然后把新帧插入对尾。

另外可以设计一个初始播放因子α,呼叫接通后,等帧缓存达到一定帧数后再开始播放,这样可以起到抗抖动的作用;α的取值为[0-1.0],当帧缓存的帧数达到α*FRAME_BUFFER_SIZE再开始播放。

 

猜你喜欢

转载自blog.csdn.net/u010178611/article/details/82625891
今日推荐