视频流jtter buffer实现的难点

背景

在项目中遇到这样一个问题,sip客户端通过监控网关去点播海康的摄像头,发现图像出来的很慢。抓包发现,码流的最开始是携带sps,pps及关键帧的,那么可以判断出问题可能是如下两点原因:

  1. 终端中的媒体库将收到的sps,pps及关键帧信息丢掉了
  2. 码流携带的sps,pps及关键帧信息有问题导致解不出来

定位

  • 通过抓包,将抓包文件中的视频码流提取出来存成文件,发现是可以播放,所以是码流有问题可能性被排除。

  • 通过调试媒体库,发现是终端媒体将码流的头几个包给丢掉了,刚好是关键帧包,所以图像出来的慢。将程序进行修改后,使其不再丢包,结果是点播摄像头时,视频图像是出来的快了,结果视频图像的效果却是会持续一段时间慢动作后,视频才能正常播放(其实即使没做如此修改了,也会出现这种问题)。最终定位到发现是jitter buffer的实现而导致了这个问题,但是改如何优化,到写这篇文章时,我还没有一个思路,现将一些想法记录如下。

媒体库中jitter buffer的功能

  1. 将乱序的包进行排序
  2. 过滤掉重复的包
  3. 等待迟到的包
  4. 针对视频包进行匀速的取数据使视频平稳的渲染播放

对第4点的实现时是需要判断帧数据和帧间间隔,那么通常是基于如下方式进行判断:

  1. 通过rtp包中的mark字段和timestamp字段获取到属于一帧图像的rtp数据
  2. 视频的采样率通常是9000HZ,所以帧间的间隔可以通过两个包的timestamp差值/90来得到,这里的单位是毫秒

通过实现分析问题

在这里插入图片描述
放数据的线程,包括如下动作:

  1. 从rtp库中的数据队列取出rtp包
  2. 对FU-A包进行处理,将FU-A的头替换为NALU的头

所以放入jitter buffer的数据就是rtp包数据,解码线程从JitterBuffer中取出数据后进行组帧及解码。

JitterBuffer本质是一个队列,开放了3个配置:

  1. 数据队列的大小
  2. 队列最大缓存的延迟
  3. 队列最小缓存的延迟

大小指的是rtp包的个数,延迟最小值到最大值即为可接受RTP延迟到达的范围,延迟单位是毫秒。有这样一个经验公式将毫秒映射为rtp的时间戳:视频帧的rtp包的时间戳间隔为3600,采样率为90000HZ,那么帧间间隔为40ms,那么将毫秒值乘以90则对应的为rtp时间戳单位的计量。

匀速取数据的问题

在我们JitterBuffer中匀速取数据只单单的通过计算帧间间隔后,再去wait。这个是有问题的,还需考虑解码耗时。因为解码耗时并不是固定的,我在测试中观察到点播的海康摄像头,摄像头参数设置的是4M,2K分辨率,其产生的I帧的FU-A包有200多个,那么解这个I帧(包括组帧)耗时肯定是比较大的。所以解码线程如果是以一个单纯的时间间隔去wait,这种情况下反而无法保证匀速。

实现难点

最大的实现难点还是在保证视频能稳定,匀速的渲染播放,难点在于以下:
数据的放和取线程间的数据同步对渲染播放的影响必须尽可能的降到最低,比如,取数据线程过快,就会造成视频效果是一卡一卡的慢动作,如果放数据线程过快,必然会导致buffer空间被填满,会产生丢数据的情况,那么视频效果看着就是突然卡顿一下

你可能感兴趣的:(流媒体)