基于IP播放TS流的码率控制策略

前言

在数字电视的应用中,TS流数据的播放是其中一个重要环节。TS流的播放从接收端的角度来考虑,是如何保证解码器的缓冲器不出现溢出;从发送端来考虑,是如何保证码流按照其自身的码率较为均匀地离开发送设备。

 

目前TS流的发送有两种方式,一种是传统的通过硬件设备,输出ASI信号,另一种是通过IP网络以IP的数据包方式进行发送。本文就后者进行讨论。

TSOverIP

通过IP网络传输TS流数据,主要是通过单播(UDP)或组播(Multicast)的方式进行传输。考虑到以太网中数据帧的最大长度为1500字节,所以TSOverIP规定,每7个TS数据包封装在一起组成一个IP包进行发送。

 

TS发送的基本原则

基于IP发送TS的基本原则是,先计算IP包发送的理论时间,再统计实际发送完时的时间,以目前百兆网卡甚至是千兆网卡的发送能力,理论发送时间应该大于实际发送时间(如果小于说明码率太大,将无法正常发送),每发送一定数量的IP包,休息一段时间,休息的这个时间为理论时间和实际发送时间之间的差值。

 

IP包理论发送时间的计为:Send_time(n) 实际发送时间可以取当前的系统时间(Sys_time)。

 

在第一次发送数据时,此时Send_time(0)为0,此时需要记录系统时间和发送时间的差值。

Distance_Send_Sys = Sys_time(0)-Send_time(0);

式中下标为IP包的索引号,下同。

 

每发送完一定数据量的IP包后,休息时间的计算公式为:

Wait_time(n)= Send_time(n)-(Sys_time(n)- Distance_Send_Sys);

 

休息时间即码流中的时间间隔和系统流逝的时间之间的差

恒码率(CBR)TS的播放策略

对于CBR的TS流,我们可以根据给定的码率计算每个IP包的发送时刻,计算公式如下:

Send_time(n) = (IP_Pack_Index * 7 * 188 * 8)/ bit_rate

在上式中Send_time(n)是第n个IP包要发送的时间;IP_Pack_Index是该IP包的索引(即下标n),从0开始,依次增加;7*188一个IP包的字节数,乘8后变成以位为单位;bit_rate是指定的码率。

 

以38M的码率为例,每个IP包发送的时间大约为:

7*188*8/38000000=0.000277(s)

考虑到计算机或其它发送设备一般都精确到毫秒级,我们可以计算一定单位时间内需要发送的IP包数,比如100ms为单位时间,需要的发送的IP包数计算公式如下:

       IP_Pack_Count =(bit_rate/10) /(188*7*8)

其中bit_rate为指定发送的码率,除10后为100ms的码率;188*7*8为一个IP数据包的位数。这样我们就得到了100ms要发送的IP包的个数,大约为361个IP包。

 

这样我们每发送完一定数量IP包后,根据“TS发送的基本原则”一节描述的计算“休息时间”的公式,休息一段时间,再继续发送下一组数据。

变码率(VBR)TS的播放策略

对VBR而言,因为码率在时刻进行变化,我们无法再根据码率进行发送。这时我们需要根据TS流中的视音频数据的DTS进行发送。

 

我们知道在TS中,一般来讲码率的变化主要是因为视频在编码时IBP帧的大小不一致导致的,而音频一般仍为固定码率,或者近似于固定码率;那么我们如何选择根据视频还是音频的DTS呢?在这里我们建议使用音频的DTS,因为在Mpeg-2标准中,定义的音频解码器的缓冲要比视频解码器的缓冲小得多,也就是说音频DTS相对于PCR的波动较视频更为严格,一旦波动越出缓冲器的大小,将会导致缓冲器溢出。

 

在VBR中,Send_time(n) 可以直接取该IP包所包含音频的DTS,每次发送的数据长度,可以取一个音频帧,也可以取几个音频帧。因为在TS流中,每个音频帧的长度为固定24ms,建议取6个音频帧,也就是144ms,因为有的复用器在打包时会直接把6个音频帧打包成一个PES包。

 

这样,我们在发送VBR时,以IP包的大小7*188为单位进行数据读取,每当该IP包包含一个音频的DTS时,将当前的DTS和上一次发送的DTS进行比较,如果大于我们指定的时间间隔(24ms或144ms),就开始发送这一组IP包,发送完成后,根据“TS发送的基本原则”一节描述的公式,计算要休息的时间。

 

总结及思考

随着TSOverIP技术的广泛应用,基于IP播放TS流将会得到更多人的关注。在本文中,我们对CBR和VBR两种TS的发送方法进行探讨,并通过实验得到了比较满意的结果。根据上述方法发送的TS流,通过VLC播放,无任何错误提示。感兴趣的读者可以试用TS-Broad的最新软件。

 

另外,基于系统时钟和DTS进行时间控制的思想,也为我们解码播放时处理音视频的同步提供了想象的空间。这个话题留给有志于解决这方面问题的开发人员进行深入的思考的吧。

参考文献

VLC 源码

我看了你的有关TS发送的理论,觉得很有道理,我自己研究了很久,都没有找到合适的方法来实现IP发送TS流,在接收端实现流畅的播放。

我根据你的理论,自己实现了一下,但是效果还是不很理想,linux下使用VLC 1.1.9在接收端播放,在其统计工具里发现音频帧持续丢失,相应的,声音的播放是断断续续的。视频还好。但是当使用VLC 2.0在windows和苹果电脑上播放时(ubuntu无法安装VLC2.0,自己编译也不行),就没问题,感觉是VLC2.0帮我修复了某个问题。

我是使用ffmpeg的库进行的转码,然后根据PCR进行发送,我不知道具体您是如何处理的,我是按照您的理论,检查两个连续的PCR之间的差,和相应的系统时间之间再次求差,若发送快了,就休息,否则就继续发送。但是不知道为什么结果还是不行。

此外,还有一个问题,就是我发现ffmpeg帮我打的PCR中,大部分PCR的base都是增加7200(80ms),但是每隔若干个,就会有两个递增3600(40ms),这还好,更有甚者是会出现个别的超级大的PCR,extention部分很大,base部分也很大,十分奇怪,没有规律,不知道是为什么?

不知道你是打算二倍发送,还是二倍播放,如果是二倍发送的话,直接把发送的时间除以2即可,比如用我们上面的算法,每个144ms处理一次,这时,反把144ms除以2,即在72ms内把这些数据发完;如果说二倍播放,那就需要做两方面的工作,一是发送端的配合,因为需要的数据量增加了两倍,二是播放端要做处理。如果播放端不是自己控制的话,可能就需要手动改每帧数据DTS和PTS了。不过我还是建议在播放端进行处理

总体上来讲,我们的思路是一致。因为通过PCR也好,通过音频的DTS也好,最终的目标其实都是得到码率。因为我们知道,对于TS来讲,如果我们认为PCR是从0开始的话,那么每个PCR就是码流播放到这个包含PCR的TS包的时间,而这个TS包的位置,即播放到这个TS包时播放的总的字节数,就是距离,空间的距离。码率的问题,简单点讲,就是公式:码率(速度)=距离/时间。

为什么说我们的思路是一致的呢?我们知道标准中规定 PCR出现的最大时间间隔不能超过40ms,通过PCR进行发送,也就是在PCR(n)-PCR(n-1)时间内把PCR(n)和PCR(n-1)之间的数据全部发送。根据上面的公式,我们有了总的字节数,有了需要发送的时间,我们可以像你说的那样计算每个TS包要发送的时间,也可以计算每16ms要发送的TS的个数。

在文章中,我为什么没有用PCR呢,是因为在实际的应用中,遇到了一些没有PCR的码流,而通过观察和实验,我发现在有PCR的码流中,音频的DTS几乎和PCR平行(音频DTS一般大于PCR 70~100ms),也就是说音频DTS的变化基本上反映了PCR的变化,根据这个特性,不管是变码率还是恒码率,其实我们都可以使用音频DTS进行发送。当然如果音频的DTS间隔过大,则另当别论。

另外,你提到空包过滤的问题,其实对于空包,我们不必做任何处理,只需把原来的码流结构进行发送即可,为什么要过滤空包呢?空包存在的目的之一,就是通过填充空包,可以把变码率的TS流变为恒码率,所在发送时不用特别处理。

经过经一步的探索, 我得到了如下的结论:
1,你的这个思路是首先要得到码率. 可是得到很准确的码率是比较困难的.
原因如下:
1)目前很多的spts是通过编码器出来的, 他的码率是比较固定的,基本上很准的.
2) 有的ts文件是通过复用器采集的.原有的4Mbps,复用后是38Mbps了,插了很多空包.
3) 有时候觉得空包太多,把所有的空包过滤了,这个是对码流伤害最大的一种.(编码器出来的码流都有空包)
感觉版主的这个方法并不上适合这些码流.
你的这个是根据码率来发送的.我目前做的是根据pcr来发送的.
当看了vlc的code后,基本上是结合码率和pcr来发送的.

1,在调试过程中,我监测了vlc的发出的码率,基本上每16毫秒都有数据,最大不会超过32毫秒. 
而版主的方法, 要wait很多,这个已经造成了stb的报告同步丢失.就是数据包不均匀.

目前的做法是, 先根据码率算出每16ms大约发多少个 7 *188的包. (这个时候码率准不准无所谓,这是粗调,将来可以通过pcr来细调)
比如码率是18Mbps的高清码率.(h264和mepg2相同) 每16ms大约发的包数为: 18000000 / 8 / (7 * 188) / (1000 * 16),假设等于XX
这个时候一般都肯定比如是8.369,我们就取8. 也就是说,每16ms大约发的包数为8,这个是比时间的码率低些.
然后我们每16ms找一个pcr, 然后比较系统时间(这个需要转换,详情请参考vlc),
如果这个pcr小于发系统时间,那下次就发 (xx++) * 7 * 188, 
如果下次找到的pcr还小那下次就发 (xx++) * 7 * 188,

如果下次pcr大于发系统时间,那下次就发 (xx--) * 7 * 188, 
注意xx--的最小值也是8.太小了不好.

结果我们的stb就可以和vlc推出的流媲美了. stb也不会报错,(以前,如果我每50ms发一次,stb就有马塞克, 但vlc发,stb是没有的.)
所有我认为版主的方法需要改进. 就写这么多吧.






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值