编码器时间戳应该在采集时打

最近接了一个活——在安卓盒子上做视音频编码网络串流。这个玩意貌似没有什么难度,live555/vlc在这方面的应用已经很多了,但是用安卓盒子来完成还是比较有挑战性的。最大的问题在于安卓系统并非实时系统,采样频率很难保证,特别是在1080p这种高分辨率的时候,采样频率无法保证的话就很难保证画面的连续性。

一开始我像大多数人那样自己造时间戳,基于编码器收上来的帧的时间,对一段时间内接收的帧求均值做为相邻两帧的时间戳delta,用VLC测试的结果并不理想,一直提示picture may delay的告警,时间长了就会导致VLC重连。后来我发现从编码器收帧的时间delta波动非常大,因为I帧大接收时间长,P帧小接收时间短,而且系统的负载对这个问题也有一定影响。这个波动越大就需要延长统计周期,从而得到一个相对平滑的值。理论上这样做问题就会得到解决,可实际上图像播放还是会出现不流畅,卡顿。最后,我意识到应该让正确的人做正确的事,这才是解决问题做有效的方法。编码时间戳本应该由采集端在采集的时候打上去,它标识了该图像发生的时刻,假设采集频率均匀,帧率足够,那么播放器只需严格按照时间戳播放就能得到流畅的画面。而实际上各个厂商的采集盒,采集频率和帧率都不是稳定的,做的好的可能波动小一点,由于波动较小,而人眼对画面之间间隔的感知有一定承受程度,所以感觉不到画面跳动/卡顿。也就是说,即使有时候相邻两帧采集时间相差了100~200ms,如果这两帧播放的时间间隔小于60ms,那么人眼都无法察觉出来。

既然知道了这个原理那问题就好办了,采集端需要讲系统做得实时,稳定,最大程度的保证采集的帧率和频率恒定。播放端根据采集端的时间戳进行调整和均衡,保证画面流畅播放。如果想要让系统适应不同播放器,也可以将时间戳调整和均衡的工作交给编码盒做。关键的一环,编码时间戳在采集的时候打。