最近我快完成我的网络监控多路控件的研发工作了,但就在这个即将圆满的关键时刻,我碰到了下面这个伤脑筋的问题。
现在自制的 RTP-MP4 网传接收的Filter已工作良好,音视频同步在实时监控的过程中也表现良好,我做了以下实验碰见了问题(注意几个实验的区别,特别是试验3、4):
实验1.开启两个GraphEdit并在其中各构件一条包含RTP-MP4 Filter的完整的网络实时监控解码回放链路,跑了一夜,两路音视频同步良好,且两路音频被声卡混音输出,停止其中的一路并不影响另外一路。(用相同的链路直接网传录像并回放录像文件,音视频同步也很好)
实验2.开启一个GraphEdit在其中构件两条包含RTP-MP4 Filter的独立完整的网络实时监控解码回放链路,也跑一夜,两路视音频同步良好,且两路音频被声卡混音输出,在一个GraphEdit中两路只能一起启动和停止。
实验3.开启一个GraphEdit在其中构件一条包含RTP-MP4 Filter的独立完整的网络实时监控解码回放链路,再开启一个单路控件(控件里构建一个包含完整网络实时监控解码回放链路的图),跑了一夜,两路音视频同步良好,且两路音频被声卡混音输出,停止其中的一路并不影响另外一路。(用相同的链路直接网传录像并回放录像文件,音视频同步也很好)
实验4.开启两个单路控件,每个控件里各自构建一个包含完整网络实时监控解码回放链路的图,相互独立,只要一跑起来就会出现:先启动的一路有声音,后启动的一路没声音,两路都有正常的图像。用TaskMgr.exe强行kill掉有声音的那一个控件,等待10分钟甚至更久,另一个控件仍然没有声音,但只要打开一个图(不管是用GraphEdit还是控件,甚至是空图)原本没声音的控件立马出声了。
另外对以上实验又作了以下工作:
1.去掉控件中所有IBasicAudio接口包括定义,问题仍然存在,现象完全一样。
2.改VMR无窗模式为有窗模式,问题仍然存在,现象完全一样。
3.在控件代码中,创建Graph对象的时候把CoCreateInstance函数中的第一个参数从CLSID_FilterGraph改为CLSID_FilterGraphNoThread后也试过,问题仍然存在,现象完全一样。
需要补充的是:在RTP-MP4 Filter模块里继承的IBaseFilter::Stop()接口方法里下断点,调试控件时发现如果同时用两个单路控件跑两路网络实时监控链路时,某一个控件中调用IMediaControl::Stop()方法,会两次进入上面的断点处,而且两次进入的分别是两个控件里的RTP-MP4 Filter模块的Stop()方法。这个现象应该可以说明一个控件里的Graph会调用另一个控件里Graph中RTP-MP4 Filter模块的Stop()方法,这是一个奇怪的现象,难道是DShow Graph的消息传递在ATL中有什么讲究?虽然一个控件里Stop的执行结果并不影响另一个控件的播放状态,(这也是令我疑惑的地方,既然被另一个Graph执行了自己的Stop,那么当前Graph为什么不会有状态改变呢?具体机制不太明白,但事实确实如此。),这个我倒不是很关心,但在音频推送的时候控件之间是不是也有类似的相互影响呢?另外视频为什么不会被影响呢?这些都让我很迷茫,当然我肯定一点问题出在控件对DShow Graph的使用上。
综上所述,用两个控件会无法同时出声的问题,我猜测是不是和ATL的线程模式或其他内部机制,导致了其中DShow Filter Graph消息循环或者控制跨越了ATL的其他实例导致的,当然现在也只是一种猜测,而且问题的位置还不明确,希望高手指点,期待小陆老师能给点建议。
=================================================================================
这篇问题贴在这有很久了吧,多久我也快忘记了。不过今天既然又看见了,就上来顶一下吧。
不能说问题已经解决了,但在最近开发项目的时候,好像有些领悟了,在这提出自己的新思路吧:
创建Graph对象的时候不使用CoCreateInstance函数,采用类工厂方法来做,这生成的Filter是可以多实例共存的,CoCreateInstance生成的多实例是会有些问题的,我在做COM开发的时候发现了这个现象。有兴趣的朋友可以参考我转载的文章《VC调用COM的方式总结》
请使用其中第三或第四种方法。