最近接到一个工作,为视频会议的视频编码增加一种VP8格式。整个流程包括VP8的编码,封包,发送,接收,解包,解码。在学习这一部分的代码时,注意到两个细节:一,对于压缩后大于1000字节的视频数据进行了拆包,既把较大的视频数据封装成多个RTP包进行发送。二,视频数据并不是拆包后立即发出,而是进入一个队列,根据一定条件进行等待后再发出。
那么,为什么要进行这两个处理呢?
背景
视频数据的特征
观察项目中的音频数据,是并没有这两个处理的。那么音频和视频有什么不同呢?
音频数据是每20ms得到一帧数据,每一帧比较小。以48000K,单声道为例,48000 * 20 / 1000,也就960个采样,每个采样16位,也就1920字节,经过压缩,肯定是小于1000字节的。
而视频数据不同,视频的数据量远远大于音频(几十甚至上百倍),特别是关键帧,一帧数据压缩后依然非常大。也就是一瞬间,会产生大量的数据待发。
RTP通常是基于UDP的
另一方面,RTP(实时传输协议)虽然可以基于不同的网络,但为了提高实时性,还是基于UDP为多。我们项目中,就是基于UDP发送的。UDP是一个无连接,不保障的网络协议。
原因解析
为什么需要拆包
UDP能接受的最大包,大约是64K左右。如果向UDP发送一个大包,会在下层自动拆分成多个包(网络底层对于包大小是有限制的,大约1500字节。)。接收端把所有拆分包都收齐以后,重新组装成UDP大包,交给应用层。然而UDP是不可靠连接,包有可能丢。如果一个大包,需要在底层拆为10个包,那么10个包里的任意一个丢失,UDP包都无法组装,从而导致整个包被丢弃。所以,可以看出,越大的包越容易丢包。而如果在应用层拆为10个包发送,丢了其中一个,不管是重传,还是通过其他方式恢复,掩盖被丢掉的那一个,都比对整个大包进行处理更容易。
为什么需要等待
UDP没有流量控制,应用程序向UDP发起发送,UDP就会立刻把数据发出去。然而,如果此时接收端的缓存满了,虽然接收端收到了数据,但是因为没地方放,就会丢掉这个数据,形成丢包。而由于视频一帧,尤其是I帧的数据量很大,如果不进行等待,一股脑全丢给网络,则很容易出现接收端到收到了前几个包,而后几个包怎么也收不到的情况。所以在发送视频数据时,应当有等待机制,发送一定量的包后,稍微等待一下,再接着发剩下的包。
UDP vs TCP
在这里顺便补充一下UDP与TCP的差别
TCP | UDP | |
---|---|---|
数据 | 面向流 | 面向消息 |
连接 | 面向连接 | 无连接 |
顺序 | 保序 | 不保序 |
到达 | 保证到达 | 不保证到达 |
流量控制 | 有 | 无 |
拥塞控制 | 有 | 无 |
延迟 | 高 | 低 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。