请教网络阻塞时,Push型网络接收Filter如何打时间戳?

时间:2021-02-08 02:20:09
我做了一个Push型的Source Filter,该filter从网络接收音视频数据包,然后一帧一帧推向下游。并且接收到的音视频帧都有正确的时间戳。

当网络状况良好,能够接收到足量数据时,按照数据包里的时间戳给Media sample打时间戳,则播放状况良好,音视频一直是同步的。

但是当网络偶然阻塞,接收不到数据,经过一段时间(比如几十秒钟)后又开始接收数据后,音视频就无法同步了,而且视频甚至一跳一跳的,看上去中间有很多丢帧似的。

不过我的Filter是有缓冲的,就是说,网络重新能够接收数据后,我的Filter会自动先缓冲足够两秒钟播放的帧,才会恢复数据流。

我的想法是:renderer根据收到的帧的时间戳,与流上的参考时钟对比,来安排播放。那么当网络暂时中断,后又恢复时,收到的帧的时间戳并不会因为这个网络中断而改变,而仍然是发送端打包时的时间戳,但是网络中断时,graph的参考时钟却仍然在走啊!所以网络传输恢复后,不管我再怎么缓冲,收到的帧的时间戳都要大大慢于参考时钟了!

我想破了脑袋也没想出该怎么办?有高人做过网络音视频接收Filter的吗?是怎样应对网络不稳定的?

不过千万不要告诉我记录下网络中断的时长,然后加到时间戳里。因为程序不可能知道网络什么中断了。

谢谢!

附:我目前的打时间戳的方法是这样的。

设接收的音频时间戳为TSa(0)....TSa(n),视频的为TSv(0)....TSv(n),
则,记录下接收到的第一个音频帧的时间戳,作为起始时间:TS_Start = TSa(0);
以后对于所有的音视频帧,有TS_CurAudioFrame_Start = TSa(n) - TS_Start,TS_CurVideoFrame_Start = TSv(n) - TS_Start。

8 个解决方案

#1


抱歉,刚才点击太快了。本来想给帖子设定100分的!我的帖子很少有不是100分的呵呵。系统说明天才能给帖子加分。

#2


其实我有一个建议可供你参考:就是你跟据音视频的缓冲来控制播放与暂停的过程。思想是这样的:
   如果其中一个缓冲小于一定的数据量,你应该调用Pause接口,因为如果你不pause的话,但是你双没有数据给它播放,这样后面来的数据就有可能是晚啦,Renderer Filter就会认为是晚到的数据,它就会丢掉,从而造成不同步。就可能出现你说的现象:(但是当网络偶然阻塞,接收不到数据,经过一段时间(比如几十秒钟)后又开始接收数据后,音视频就无法同步了,而且视频甚至一跳一跳的,看上去中间有很多丢帧似的)
   所以你检查一下你没有数据播放 的时候filter是不是pause状态,不是的话,自己调用pause,然后有数据再Run。因为没有数据而Run,Graph的流时间不会停的。
   按你这里面的理解:(graph的参考时钟却仍然在走啊!所以网络传输恢复后,不管我再怎么缓冲,收到的帧的时间戳都要大大慢于参考时钟了)你应该知道你一点的呀!

#3


首先感谢zhangchaoyszq对我的困难关心,谢谢!

那么你的意思是,在这种播放网络流的应用里,除了Graph及里面的Filters之外,调用程序也应该介入,并给予一定的帮助是吗?

我估计你的意思是负责接收数据的Source filter自己在接收线程里pause或者resume graph。反正不管谁来干预,总之是要有一个第三方根据接收缓冲区里的库存状况来干预一下Graph?

我理解你的意思了,但是真的是这样吗??是真的?所有基于dshow的网络接收程序都是这样做的?

那些嵌入网页里的,用于播放在线视频的控件(可能是媒播的控件吧)也是这么做的?因为我总觉得,如果需要第三方介入干预Graph才能正常播放的话,那么明显说明dshow架构设计的不到位嘛,不应该呀?~~

#4


关注!

另外,lz说“不过千万不要告诉我记录下网络中断的时长,然后加到时间戳里。因为程序不可能知道网络什么中断了。 ”
能不能通过监测缓冲区内数据包的个数来判断网络是否通畅?

#5


我觉得所谓网络中断,应该是中断到无法播放的程度。如果仅仅监视接收缓冲区的库存量,则不能确定是否已经没有数据可播放,因为Renderer里面也有缓冲的。总之,给时间戳加时间偏移的方法我看是行不通的了。

#6


呵呵,我刚才在实验zhangchaoyszq说的pause的方法时,无意中又发现,Graph只要一Stop,再重新Play,视频流就不跑了,每次Deliver就半天不返回,只有声音还在正常继续。可是重新Play时我的时间戳明明是恢复从0开始的啊。第一次Play就是好的,Stop之后再Play就不正常了。

我现在已经开始严重怀疑DirectShow架构了。什么玩意啊这是!Quartz.dll里面都是些什么豆腐渣啊,CaoTaMaDe......

#7


lz问题解决没?renderer里面应该没有缓冲的

#8


lz的问题没有解决,只能继续等待了。

以前一直在用DShow做本地摄像头应用软件,感觉DShow既简单又强大。

这次做了个网络接收的项目(不是互联网的,是卫星广播的),才发现DShow问题一箩筐。当然,肯定是因为我对DShow的了解有限造成的。但是这个理由无法为DShow开脱。因为如果DShow真的很好很强大,就不应该造成我现在的苦难,毕竟,我已经翻遍了手头上的以及网络上的资料和帖子了。再不行,就是DShow的毛病了不是?

最后,xj,renderers要想实现影音同步,就一定要有缓冲,虽然我很懒没有好好看过CBaseRender的代码,但是想一想也知道的——链路上的各个Transforms都要耗时间,如果Push source或者Parser(splitter)不能尽快的把足量的samples提前发到renderers,那renderers又如何安排同步呢?比如说,30fps的视频,每帧33ms。但是加上链路上拷贝、转换数据,链路就不容易保证以33ms一圈的速度跑了。(纯属个人理解啊)

#1


抱歉,刚才点击太快了。本来想给帖子设定100分的!我的帖子很少有不是100分的呵呵。系统说明天才能给帖子加分。

#2


其实我有一个建议可供你参考:就是你跟据音视频的缓冲来控制播放与暂停的过程。思想是这样的:
   如果其中一个缓冲小于一定的数据量,你应该调用Pause接口,因为如果你不pause的话,但是你双没有数据给它播放,这样后面来的数据就有可能是晚啦,Renderer Filter就会认为是晚到的数据,它就会丢掉,从而造成不同步。就可能出现你说的现象:(但是当网络偶然阻塞,接收不到数据,经过一段时间(比如几十秒钟)后又开始接收数据后,音视频就无法同步了,而且视频甚至一跳一跳的,看上去中间有很多丢帧似的)
   所以你检查一下你没有数据播放 的时候filter是不是pause状态,不是的话,自己调用pause,然后有数据再Run。因为没有数据而Run,Graph的流时间不会停的。
   按你这里面的理解:(graph的参考时钟却仍然在走啊!所以网络传输恢复后,不管我再怎么缓冲,收到的帧的时间戳都要大大慢于参考时钟了)你应该知道你一点的呀!

#3


首先感谢zhangchaoyszq对我的困难关心,谢谢!

那么你的意思是,在这种播放网络流的应用里,除了Graph及里面的Filters之外,调用程序也应该介入,并给予一定的帮助是吗?

我估计你的意思是负责接收数据的Source filter自己在接收线程里pause或者resume graph。反正不管谁来干预,总之是要有一个第三方根据接收缓冲区里的库存状况来干预一下Graph?

我理解你的意思了,但是真的是这样吗??是真的?所有基于dshow的网络接收程序都是这样做的?

那些嵌入网页里的,用于播放在线视频的控件(可能是媒播的控件吧)也是这么做的?因为我总觉得,如果需要第三方介入干预Graph才能正常播放的话,那么明显说明dshow架构设计的不到位嘛,不应该呀?~~

#4


关注!

另外,lz说“不过千万不要告诉我记录下网络中断的时长,然后加到时间戳里。因为程序不可能知道网络什么中断了。 ”
能不能通过监测缓冲区内数据包的个数来判断网络是否通畅?

#5


我觉得所谓网络中断,应该是中断到无法播放的程度。如果仅仅监视接收缓冲区的库存量,则不能确定是否已经没有数据可播放,因为Renderer里面也有缓冲的。总之,给时间戳加时间偏移的方法我看是行不通的了。

#6


呵呵,我刚才在实验zhangchaoyszq说的pause的方法时,无意中又发现,Graph只要一Stop,再重新Play,视频流就不跑了,每次Deliver就半天不返回,只有声音还在正常继续。可是重新Play时我的时间戳明明是恢复从0开始的啊。第一次Play就是好的,Stop之后再Play就不正常了。

我现在已经开始严重怀疑DirectShow架构了。什么玩意啊这是!Quartz.dll里面都是些什么豆腐渣啊,CaoTaMaDe......

#7


lz问题解决没?renderer里面应该没有缓冲的

#8


lz的问题没有解决,只能继续等待了。

以前一直在用DShow做本地摄像头应用软件,感觉DShow既简单又强大。

这次做了个网络接收的项目(不是互联网的,是卫星广播的),才发现DShow问题一箩筐。当然,肯定是因为我对DShow的了解有限造成的。但是这个理由无法为DShow开脱。因为如果DShow真的很好很强大,就不应该造成我现在的苦难,毕竟,我已经翻遍了手头上的以及网络上的资料和帖子了。再不行,就是DShow的毛病了不是?

最后,xj,renderers要想实现影音同步,就一定要有缓冲,虽然我很懒没有好好看过CBaseRender的代码,但是想一想也知道的——链路上的各个Transforms都要耗时间,如果Push source或者Parser(splitter)不能尽快的把足量的samples提前发到renderers,那renderers又如何安排同步呢?比如说,30fps的视频,每帧33ms。但是加上链路上拷贝、转换数据,链路就不容易保证以33ms一圈的速度跑了。(纯属个人理解啊)